Skip to content

Commit

Permalink
Add support for fans (HAFan) (#18)
Browse files Browse the repository at this point in the history
* finished basic implementation of the HAFan

* add retain method to DeviceTypeSerializer

* finished HAFan implementation

* update HAHVAC

* device types cleanup

* add HAFan example

* update changelog

* update readme

* update fan example
  • Loading branch information
dawidchyrzynski authored Mar 21, 2021
1 parent 4bc9f78 commit b2e7003
Show file tree
Hide file tree
Showing 22 changed files with 740 additions and 295 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
## 1.2.0

**Breaking changes:**
* Refactored HASensor implementation. Please take a look at updated example in `eamples/sensor/sensor.ino`
* Refactored HASensor implementation. Please take a look at updated example in `examples/sensor/sensor.ino`

**New features:**
* Added support for HVAC
* Added support for excluding devices types from the compilation using defines (see `src/ArduinoHADefines.h`)
* Added support for setting icon in HASwitch and HASensor
* Added support for setting retain flag in HASwitch
* Added support for text (const char*) payload in HASensor
* Added support for fans (HAFan)

**Updates:**
* Optimized codebase and logic in all devices types
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ but I successfully use it on ESP8266/ESP8255 boards in my projects.
## Examples

* [Binary Sensor](examples/binary-sensor/binary-sensor.ino)
* [Fan](examples/fan/fan.ino)
* [LED switch](examples/led-switch/led-switch.ino)
* [MQTT with credentials](examples/mqtt-with-credentials/mqtt-with-credentials.ino)
* [Multi-state button](examples/multi-state-button/multi-state-button.ino)
Expand Down Expand Up @@ -40,6 +41,7 @@ but I successfully use it on ESP8266/ESP8255 boards in my projects.
## Supported HA types

* Binary sensors
* Fans
* Device triggers
* Switches
* Sensors
Expand Down
58 changes: 58 additions & 0 deletions examples/fan/fan.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <Ethernet.h>
#include <ArduinoHA.h>

#define BROKER_ADDR IPAddress(192,168,0,17)

byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};

EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);

// HAFan::SpeedsFeature enables support for setting different speeds of fan.
// You can skip this argument if you don't need speed management.
HAFan fan("ventilation", HAFan::SpeedsFeature);

void onStateChanged(bool state) {
Serial.print("State: ");
Serial.println(state);
}

void onSpeedChanged(HAFan::Speed speed) {
Serial.print("Speed: ");
if (speed == HAFan::OffSpeed) {
Serial.print("off");
} else if (speed == HAFan::LowSpeed) {
Serial.print("low");
} else if (speed == HAFan::MediumSpeed) {
Serial.print("medium");
} else if (speed == HAFan::HighSpeed) {
Serial.print("high");
}
}

void setup() {
// you don't need to verify return status
Ethernet.begin(mac);

// set device's details (optional)
device.setName("Arduino");
device.setSoftwareVersion("1.0.0");

// configure fan (optional)
// default speeds are: Off | Low | Medium | High
fan.setSpeeds(HAFan::OffSpeed | HAFan::LowSpeed | HAFan::HighSpeed);
fan.setName("Bathroom");
fan.setRetain(true);

// handle fan states
fan.onStateChanged(onStateChanged);
fan.onSpeedChanged(onSpeedChanged);

mqtt.begin(BROKER_ADDR);
}

void loop() {
Ethernet.maintain();
mqtt.loop();
}
1 change: 1 addition & 0 deletions src/ArduinoHA.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "HAMqtt.h"
#include "HAUtils.h"
#include "device-types/HABinarySensor.h"
#include "device-types/HAFan.h"
#include "device-types/HAHVAC.h"
#include "device-types/HASensor.h"
#include "device-types/HASwitch.h"
Expand Down
1 change: 1 addition & 0 deletions src/ArduinoHADefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

// You can reduce Flash size of the compiled library by commenting unused components below
#define ARDUINOHA_BINARY_SENSOR
#define ARDUINOHA_FAN
#define ARDUINOHA_HVAC
#define ARDUINOHA_SENSOR
#define ARDUINOHA_SWITCH
Expand Down
46 changes: 46 additions & 0 deletions src/device-types/BaseDeviceType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,52 @@ void BaseDeviceType::onMqttMessage(
(void)length;
}

void BaseDeviceType::publishConfig()
{
const HADevice* device = mqtt()->getDevice();
if (device == nullptr) {
return;
}

const uint16_t& deviceLength = device->calculateSerializedLength();
if (deviceLength == 0) {
return;
}

char serializedDevice[deviceLength];
if (device->serialize(serializedDevice) == 0) {
return;
}

const uint16_t& topicLength = DeviceTypeSerializer::calculateTopicLength(
componentName(),
name(),
DeviceTypeSerializer::ConfigTopic
);
const uint16_t& dataLength = calculateSerializedLength(serializedDevice);

if (topicLength == 0 || dataLength == 0) {
return;
}

char topic[topicLength];
DeviceTypeSerializer::generateTopic(
topic,
componentName(),
name(),
DeviceTypeSerializer::ConfigTopic
);

if (strlen(topic) == 0) {
return;
}

if (mqtt()->beginPublish(topic, dataLength, true)) {
writeSerializedData(serializedDevice);
mqtt()->endPublish();
}
}

void BaseDeviceType::publishAvailability()
{
if (_availability == AvailabilityDefault ||
Expand Down
3 changes: 3 additions & 0 deletions src/device-types/BaseDeviceType.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ class BaseDeviceType
const uint16_t& length
);

virtual void publishConfig();
virtual void publishAvailability();
virtual bool isMyTopic(const char* topic, const char* expectedTopic);
virtual uint16_t calculateSerializedLength(const char* serializedDevice) const = 0;
virtual bool writeSerializedData(const char* serializedDevice) const = 0;

const char* const _componentName;
const char* const _name;
Expand Down
26 changes: 26 additions & 0 deletions src/device-types/DeviceTypeSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ uint16_t DeviceTypeSerializer::calculateAvailabilityFieldSize(
return availabilityTopicLength + 12; // 12 - length of the JSON decorators for this field
}

uint16_t DeviceTypeSerializer::calculateRetainFieldSize(bool retain)
{
if (!retain) {
return 0;
}

// Field format: ,"ret":true
return 11;
}

uint16_t DeviceTypeSerializer::calculateDeviceFieldSize(
const char* serializedDevice
)
Expand Down Expand Up @@ -245,6 +255,22 @@ void DeviceTypeSerializer::mqttWriteAvailabilityField(
mqttWriteConstCharField(Prefix, availabilityTopic);
}

void DeviceTypeSerializer::mqttWriteRetainField(
bool retain
)
{
if (!retain) {
return;
}

static const char Prefix[] PROGMEM = {",\"ret\":"};
mqttWriteConstCharField(
Prefix,
"true",
false
);
}

void DeviceTypeSerializer::mqttWriteDeviceField(
const char* serializedDevice
)
Expand Down
6 changes: 6 additions & 0 deletions src/device-types/DeviceTypeSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class DeviceTypeSerializer
static uint16_t calculateAvailabilityFieldSize(
const BaseDeviceType* const dt
);
static uint16_t calculateRetainFieldSize(
bool retain
);
static uint16_t calculateDeviceFieldSize(
const char* serializedDevice
);
Expand All @@ -83,6 +86,9 @@ class DeviceTypeSerializer
static void mqttWriteAvailabilityField(
const BaseDeviceType* const dt
);
static void mqttWriteRetainField(
bool retain
);
static void mqttWriteDeviceField(
const char* serializedDevice
);
Expand Down
46 changes: 0 additions & 46 deletions src/device-types/HABinarySensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,52 +74,6 @@ bool HABinarySensor::setState(bool state)
return false;
}

void HABinarySensor::publishConfig()
{
const HADevice* device = mqtt()->getDevice();
if (device == nullptr) {
return;
}

const uint16_t& deviceLength = device->calculateSerializedLength();
if (deviceLength == 0) {
return;
}

char serializedDevice[deviceLength];
if (device->serialize(serializedDevice) == 0) {
return;
}

const uint16_t& topicLength = DeviceTypeSerializer::calculateTopicLength(
componentName(),
name(),
DeviceTypeSerializer::ConfigTopic
);
const uint16_t& dataLength = calculateSerializedLength(serializedDevice);

if (topicLength == 0 || dataLength == 0) {
return;
}

char topic[topicLength];
DeviceTypeSerializer::generateTopic(
topic,
componentName(),
name(),
DeviceTypeSerializer::ConfigTopic
);

if (strlen(topic) == 0) {
return;
}

if (mqtt()->beginPublish(topic, dataLength, true)) {
writeSerializedData(serializedDevice);
mqtt()->endPublish();
}
}

bool HABinarySensor::publishState(bool state)
{
if (strlen(name()) == 0) {
Expand Down
5 changes: 2 additions & 3 deletions src/device-types/HABinarySensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ class HABinarySensor : public BaseDeviceType
{ return _currentState; }

private:
void publishConfig();
bool publishState(bool state);
uint16_t calculateSerializedLength(const char* serializedDevice) const;
bool writeSerializedData(const char* serializedDevice) const;
uint16_t calculateSerializedLength(const char* serializedDevice) const override;
bool writeSerializedData(const char* serializedDevice) const override;

const char* _class;
bool _currentState;
Expand Down
Loading

0 comments on commit b2e7003

Please sign in to comment.