muwerk mupplet Core Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications
Loading...
Searching...
No Matches
home_assistant.h
1// home_assistant.h - muwerk HomeAssistant Autodiscovery Manager
2#pragma once
3
4#include "muwerk.h"
5#include "mupplet_core.h"
6#include "jsonfile.h"
7
8#define USTD_FEATURE_HOMEASSISTANT
9
10namespace ustd {
87 public:
88 static const char *version; // = "0.1.0";
89
92 Unknown = -1,
93 Sensor = 0,
102 };
103
104 private:
105 // internal type definitions
106 typedef struct {
107 const char *name;
108 const char *manufacturer;
109 const char *model;
110 const char *version;
111 } Attributes;
112
113 typedef struct {
114 DeviceType type;
115 const char *name;
116 const char *value;
117 const char *human;
118 const char *unit;
119 const char *icon;
120 const char *val_tpl;
121 const char *attribs;
122 const char *effects;
123 const char *dev_cla;
124 int channel;
125 int off_dly;
126 int exp_aft;
127 bool frc_upd;
128 } Entity;
129
130 // muwerk task management
131 Scheduler *pSched;
132 int tID = SCHEDULER_MAIN;
133
134#ifdef USTD_FEATURE_FILESYSTEM
135 // configuration management
136 jsonfile config;
137#endif
138
139 // device data
140 String deviceName;
141 String deviceManufacturer;
142 String deviceModel;
143 String deviceVersion;
144 String deviceId;
145 String haTopicAttrib = "ha/attribs/";
146 String haTopicConfig = "!!homeassistant/";
147
148 // runtime - states
149 bool autodiscovery = false;
150 bool connected = false;
151 long rssiVal = -99;
152 String macAddress;
153 String ipAddress;
154 String hostName;
155 String pathPrefix;
156 String lastWillTopic;
157 String lastWillMessage;
158
159 // runtime - device data
160 ustd::array<Attributes> attribGroups;
161 ustd::array<Entity> entityConfigs;
162
163 public:
173 HomeAssistant(String name, String manufacturer, String model, String version)
174 : deviceName(name), deviceManufacturer(manufacturer), deviceModel(model),
175 deviceVersion(version) {
176 }
177
178 virtual ~HomeAssistant() {
179 for (unsigned int i = 0; i < attribGroups.length(); i++) {
180 free((void *)attribGroups[i].name);
181 }
182 for (unsigned int i = 0; i < entityConfigs.length(); i++) {
183 free((void *)entityConfigs[i].name);
184 }
185 }
186
193 void begin(Scheduler *_pSched, bool initialAutodiscovery = false) {
194 pSched = _pSched;
195
196 // initialize configuration
197#ifdef USTD_FEATURE_FILESYSTEM
198 autodiscovery = config.readBool("ha/autodiscovery", initialAutodiscovery);
199 if ((deviceId = config.readString("net/deviceid")) == "") {
200 // initialize device id to mac address
201 deviceId = WiFi.macAddress();
202 deviceId.replace(":", "");
203 }
204#else
205 autodiscovery = initialAutodiscovery;
206 deviceId = WiFi.macAddress();
207 deviceId.replace(":", "");
208#endif
209
210 // try to initialze some stuff
211 addAttributes("device");
212
213 // react to network state changes
214 pSched->subscribe(tID, "mqtt/config", [this](String topic, String msg, String orig) {
215 this->onMqttConfig(topic, msg, orig);
216 });
217 pSched->subscribe(tID, "mqtt/state", [this](String topic, String msg, String orig) {
218 this->onMqttState(topic, msg, orig);
219 });
220 pSched->subscribe(tID, "net/network", [this](String topic, String msg, String orig) {
221 this->onNetNetwork(topic, msg, orig);
222 });
223 pSched->subscribe(tID, "net/rssi", [this](String topic, String msg, String orig) {
224 this->onNetRssi(topic, msg, orig);
225 });
226
227 // react to commands
228 pSched->subscribe(tID, "ha/state/#", [this](String topic, String msg, String originator) {
229 this->onCommand(topic.substring(11), msg);
230 });
231
232 // request current state
233 pSched->publish("net/network/get");
234 pSched->publish("mqtt/state/get");
235
236 // publish out current state
237 publishState();
238 }
239
243 void setAutoDiscovery(bool enabled) {
244 if (autodiscovery != enabled) {
245 autodiscovery = enabled;
246 updateHA();
247 }
248 publishState();
249#ifdef USTD_FEATURE_FILESYSTEM
250 config.writeBool("ha/autodiscovery", autodiscovery);
251#endif
252 }
253
271 void addAttributes(String attribGroup, String manufacturer = "", String model = "",
272 String version = "") {
273
274 for (unsigned int i = 0; i < attribGroups.length(); i++) {
275 if (attribGroup == attribGroups[i].name) {
276 // insert only unique attribute groups
277 return;
278 }
279 }
280
281 Attributes att = {};
282 String *man = manufacturer.length() ? &manufacturer : &deviceManufacturer;
283 String *mod = model.length() ? &model : &deviceModel;
284 String *ver = version.length() ? &version : &deviceVersion;
285
286 att.name = (char *)malloc(attribGroup.length() + man->length() + mod->length() +
287 ver->length() + 4);
288 if (att.name) {
289 att.manufacturer = copyfieldgetnext(att.name, attribGroup);
290 att.model = copyfieldgetnext(att.manufacturer, *man);
291 att.version = copyfieldgetnext(att.model, *mod);
292 strcpy((char *)att.version, ver->c_str());
293 if (attribGroups.add(att) == -1) {
294 free((void *)att.name);
295 }
296 }
297 }
298
313 void addSwitch(String name, String human = "", String dev_cla = "", String icon = "",
314 String attribs = "") {
315 addGenericActor(Switch, name, -1, human, dev_cla, icon, attribs);
316 }
317
333 void addSwitch(String name, int channel, String human = "", String dev_cla = "",
334 String icon = "", String attribs = "") {
335 if (channel >= 0) {
336 addGenericActor(Switch, name, channel, human, dev_cla, icon, attribs);
337 }
338 }
339
355 void addMultiSwitch(String name, int count, String human = "", String dev_cla = "",
356 String icon = "", String attribs = "") {
357 if (count > 1) {
358 addGenericActor(Switch, name, -count, human, dev_cla, icon, attribs);
359 }
360 }
361
377 void addLight(String name, String human = "", DeviceType type = LightDim, String icon = "",
378 String attribs = "", String effects = "") {
379 if (type >= Light && type <= LightRGBWW) {
380 addGenericActor(type, name, -1, human, "", icon, attribs, effects);
381 }
382 }
383
400 void addLight(String name, int channel, String human = "", DeviceType type = LightDim,
401 String icon = "", String attribs = "", String effects = "") {
402 if (channel >= 0 && type >= Light && type <= LightRGBWW) {
403 addGenericActor(type, name, channel, human, "", icon, attribs, effects);
404 }
405 }
406
422 void addMultiLight(String name, int count, String human = "", DeviceType type = LightDim,
423 String icon = "", String attribs = "") {
424 if (count > 1 && type >= Light && type <= LightRGBWW) {
425 addGenericActor(type, name, -count, human, "", icon, attribs);
426 }
427 }
428
448 void addSensor(String name, String value, String human = "", String dev_cla = "",
449 String unit = "", String icon = "", String val_tpl = "", int exp_aft = -1,
450 bool frc_upd = false, String attribs = "") {
451 addGenericSensor(Sensor, name, value, -1, human, dev_cla, unit, icon, val_tpl, exp_aft,
452 frc_upd, -1, attribs);
453 }
454
475 void addSensor(String name, String value, int channel, String human = "", String dev_cla = "",
476 String unit = "", String icon = "", String val_tpl = "", int exp_aft = -1,
477 bool frc_upd = false, String attribs = "") {
478 if (channel >= 0) {
479 addGenericSensor(Sensor, name, value, channel, human, dev_cla, unit, icon, val_tpl,
480 exp_aft, frc_upd, -1, attribs);
481 }
482 }
483
504 void addMultiSensor(String name, String value, int count, String human = "",
505 String dev_cla = "", String unit = "", String icon = "",
506 String val_tpl = "", int exp_aft = -1, bool frc_upd = false,
507 String attribs = "") {
508 if (count > 1) {
509 addGenericSensor(Sensor, name, value, -count, human, dev_cla, unit, icon, val_tpl,
510 exp_aft, frc_upd, -1, attribs);
511 }
512 }
513
535 void addBinarySensor(String name, String value, String human = "", String dev_cla = "",
536 String unit = "", String icon = "", String val_tpl = "", int exp_aft = -1,
537 bool frc_upd = false, int off_dly = -1, String attribs = "") {
538 addGenericSensor(BinarySensor, name, value, -1, human, dev_cla, unit, icon, val_tpl,
539 exp_aft, frc_upd, off_dly, attribs);
540 }
541
564 void addBinarySensor(String name, String value, int channel, String human = "",
565 String dev_cla = "", String unit = "", String icon = "",
566 String val_tpl = "", int exp_aft = -1, bool frc_upd = false,
567 int off_dly = -1, String attribs = "") {
568 if (channel >= 0) {
569 addGenericSensor(BinarySensor, name, value, channel, human, dev_cla, unit, icon,
570 val_tpl, exp_aft, frc_upd, off_dly, attribs);
571 }
572 }
573
596 void addMultiBinarySensor(String name, String value, int count, String human = "",
597 String dev_cla = "", String unit = "", String icon = "",
598 String val_tpl = "", int exp_aft = -1, bool frc_upd = false,
599 int off_dly = -1, String attribs = "") {
600 if (count > 1) {
601 addGenericSensor(BinarySensor, name, value, -count, human, dev_cla, unit, icon, val_tpl,
602 exp_aft, frc_upd, off_dly, attribs);
603 }
604 }
605
606 protected:
607 void onMqttConfig(String topic, String msg, String originator) {
608 if (originator == "mqtt") {
609 return;
610 }
611 pathPrefix = shift(msg, '+');
612 lastWillTopic = shift(msg, '+');
613 lastWillMessage = shift(msg, '+');
614 }
615
616 void onMqttState(String topic, String msg, String originator) {
617 if (originator == "mqtt") {
618 return;
619 }
620 bool previous = connected;
621 connected = msg == "connected";
622 if (connected != previous) {
623 updateHA();
624 }
625 }
626
627 void onNetNetwork(String topic, String msg, String originator) {
628 if (originator == "mqtt") {
629 return;
630 }
631 JSONVar mqttMsg = JSON.parse(msg);
632 if (JSON.typeof(mqttMsg) == "undefined") {
633 return;
634 }
635 if (!strcmp((const char *)mqttMsg["state"], "connected")) {
636 ipAddress = (const char *)mqttMsg["ip"];
637 macAddress = (const char *)mqttMsg["mac"];
638 hostName = (const char *)mqttMsg["hostname"];
639 }
640 }
641
642 void onNetRssi(String topic, String msg, String originator) {
643 if (originator == "mqtt") {
644 return;
645 }
646 rssiVal = parseLong(msg, 0);
647 if (autodiscovery) {
648 publishAttribs();
649 }
650 }
651
652 void onCommand(String topic, String msg) {
653 if (topic == "get") {
654 publishState();
655 } else if (topic == "set") {
656 msg.trim();
657 msg.toLowerCase();
658 if (msg == "on" || msg == "true") {
659 setAutoDiscovery(true);
660 } else if (msg == "off" || msg == "false") {
661 setAutoDiscovery(false);
662 }
663 }
664 }
665
666 void addGenericActor(DeviceType type, String name, int channel, String human = "",
667 String dev_cla = "", String icon = "", String attribs = "", String effects = "") {
668 size_t len = name.length() + human.length() + dev_cla.length() + icon.length() +
669 attribs.length() + effects.length() + 6;
670 Entity entity = {};
671 entity.name = (const char *)malloc(len);
672 if (entity.name) {
673 entity.type = type;
674 entity.channel = channel;
675 entity.human = copyfieldgetnext(entity.name, name);
676 entity.dev_cla = copyfieldgetnext(entity.human, human);
677 entity.icon = copyfieldgetnext(entity.dev_cla, dev_cla);
678 entity.attribs = copyfieldgetnext(entity.icon, icon);
679 entity.effects = copyfieldgetnext(entity.attribs, attribs);
680 copyfieldgetnext(entity.effects, effects);
681 if (entityConfigs.add(entity) == -1) {
682 free((void *)entity.name);
683 }
684 }
685 }
686
687 void addGenericSensor(DeviceType type, String name, String value, int channel,
688 String human = "", String dev_cla = "", String unit = "",
689 String icon = "", String val_tpl = "", int exp_aft = -1,
690 bool frc_upd = false, int off_dly = -1, String attribs = "") {
691 size_t len = name.length() + value.length() + human.length() + dev_cla.length() +
692 unit.length() + icon.length() + val_tpl.length() + attribs.length() + 8;
693
694 Entity entity = {};
695 entity.name = (const char *)malloc(len);
696 if (entity.name) {
697 entity.type = type;
698 entity.channel = channel;
699 entity.value = copyfieldgetnext(entity.name, name);
700 entity.human = copyfieldgetnext(entity.value, value);
701 entity.dev_cla = copyfieldgetnext(entity.human, human);
702 entity.unit = copyfieldgetnext(entity.dev_cla, dev_cla);
703 entity.icon = copyfieldgetnext(entity.unit, unit);
704 entity.val_tpl = copyfieldgetnext(entity.icon, icon);
705 entity.attribs = copyfieldgetnext(entity.val_tpl, val_tpl);
706 copyfieldgetnext(entity.attribs, attribs);
707 entity.off_dly = off_dly;
708 entity.exp_aft = exp_aft;
709 entity.frc_upd = frc_upd;
710 if (entityConfigs.add(entity) == -1) {
711 free((void *)entity.name);
712 }
713 }
714 }
715
716 static const char *getDeviceClass(DeviceType type) {
717 switch (type) {
718 default:
719 return "sensor";
721 return "binary_sensor";
728 return "light";
730 return "switch";
731 }
732 }
733
734 String getConfigTopic(DeviceType type, const char *uniq_id) {
735 return haTopicConfig + getDeviceClass(type) + "/" + uniq_id + "/config";
736 }
737
738 void flushDeviceConfig(DeviceType type, JSONVar &msg) {
739 msg["dev"]["ids"][0] = deviceId;
740 msg["dev"]["name"] = deviceName;
741 msg["dev"]["mf"] = deviceManufacturer;
742 msg["dev"]["mdl"] = deviceModel;
743 msg["dev"]["sw"] = deviceVersion;
744 // too much of goodness...
745 // msg["dev"]["cns"][0][0] = "IP";
746 // msg["dev"]["cns"][0][1] = ipAddress;
747 // msg["dev"]["cns"][1][0] = "Host";
748 // msg["dev"]["cns"][1][1] = hostName;
749 pSched->publish(getConfigTopic(type, msg["uniq_id"]), JSON.stringify(msg));
750 // Serial.println("TOPIC:" + getConfigTopic(type, msg["uniq_id"]));
751 // Serial.println(" " + JSON.stringify(msg));
752 }
753
754 void publishDeviceConfig() {
755 JSONVar msg;
756 msg["~"] = pathPrefix + "/";
757 msg["name"] = hostName + " Status";
758 msg["stat_t"] = "~ha/attribs/device";
759 msg["avty_t"] = "~mqtt/state";
760 msg["pl_avail"] = "connected";
761 msg["pl_not_avail"] = lastWillMessage;
762 msg["json_attr_t"] = "~ha/attribs/device";
763 msg["unit_of_meas"] = "%";
764 msg["val_tpl"] = "{{value_json['RSSI']}}";
765 msg["ic"] = "mdi:information-outline";
766 msg["uniq_id"] = deviceId + "_status";
767 flushDeviceConfig(DeviceType::Sensor, msg);
768 }
769
770 static String getEntityName(Entity &entity) {
771 if (entity.human && *entity.human) {
772 return entity.human;
773 } else if (entity.value && *entity.value) {
774 return String(entity.name) + " " + entity.value;
775 } else {
776 return entity.name;
777 }
778 }
779
780 String getEntityKey(Entity &entity) {
781 String retVal;
782 if (entity.value && *entity.value) {
783 retVal = deviceId + "_" + entity.name + "_" + entity.value;
784 } else {
785 retVal = deviceId + "_" + entity.name;
786 }
787 retVal.replace(" ", "_");
788 return retVal;
789 }
790
791 static String getEntityTopic(Entity &entity) {
792 String entityTopic = entity.name;
793 entityTopic.concat("/");
794 entityTopic.concat(getDeviceClass(entity.type));
795 entityTopic.replace(" ", "_");
796 return entityTopic;
797 }
798
799 void publishConfigs() {
800 // device config
801 publishDeviceConfig();
802
803 // entity configs
804 for (unsigned int i = 0; i < entityConfigs.length(); i++) {
805 publishConfig(entityConfigs[i]);
806 }
807 }
808
809 void publishConfig(Entity &entity) {
810 String name = getEntityName(entity);
811 String key = getEntityKey(entity);
812 String topic = getEntityTopic(entity);
813
814 if (entity.channel == -1) {
815 publishConfig(entity, name, key, topic);
816 } else if (entity.channel < -1) {
817 for (int i = 0; i < abs(entity.channel); i++) {
818 publishConfig(entity, name + "." + i, key + "_" + i, topic + "/" + i);
819 }
820 } else {
821 int i = entity.channel;
822 publishConfig(entity, name + "." + i, key + "_" + i, topic + "/" + i);
823 }
824 }
825
826 void publishConfig(Entity &entity, String name, String key, String topic) {
827 JSONVar msg;
828 msg["~"] = pathPrefix + "/";
829 msg["name"] = hostName + " " + name;
830 msg["uniq_id"] = key;
831 msg["avty_t"] = "~mqtt/state";
832 msg["pl_avail"] = "connected";
833 msg["pl_not_avail"] = lastWillMessage;
834 msg["json_attr_t"] = "~" + haTopicAttrib + (*entity.attribs ? entity.attribs : "device");
835 if (*entity.dev_cla) {
836 msg["dev_cla"] = entity.dev_cla;
837 }
838 if (*entity.icon) {
839 msg["ic"] = entity.icon;
840 }
841 switch (entity.type) {
842 // case DeviceType::Cover:
843 // publishCoverConfig(msg, entity, topic);
844 // break;
851 publishLightConfig(msg, entity, topic);
852 break;
853 case DeviceType::Sensor:
855 publishSensorConfig(msg, entity, topic);
856 break;
858 publishSwitchConfig(msg, entity, topic);
859 break;
860 default:
861 break;
862 }
863 }
864
865 void publishLightConfig(JSONVar &msg, Entity &entity, String &topic) {
866 msg["stat_t"] = "~" + topic + "/state";
867 msg["cmd_t"] = hostName + "/" + topic + "/set";
868 msg["payload_on"] = "on";
869 msg["payload_off"] = "off";
870
871 if (entity.type == LightDim || entity.type == LightWW) {
872 // add support for brightness
873 msg["bri_cmd_t"] = hostName + "/" + topic + "/set";
874 msg["bri_scl"] = "100";
875 msg["bri_stat_t"] = "~" + topic + "/unitbrightness";
876 msg["bri_val_tpl"] = "{{ value | float * 100 | round(0) }}";
877 msg["on_cmd_type"] = "brightness";
878 }
879 if (entity.type == LightRGB || entity.type == LightRGBW || entity.type == LightRGBWW) {
880 // add support for brightness
881 msg["bri_cmd_t"] = hostName + "/" + topic + "/set";
882 msg["bri_scl"] = "100";
883 msg["bri_stat_t"] = "~" + topic + "/unitbrightness";
884 msg["bri_val_tpl"] = "{{ value | float * 100 | round(0) }}";
885 msg["on_cmd_type"] = "first";
886 // color
887 msg["color_mode"] = true;
888 switch (entity.type) {
889 case LightRGB:
890 msg["supported_color_modes"] = {"rgb"};
891 break;
892 case LightRGBW:
893 msg["supported_color_modes"] = {"rgbw"};
894 break;
895 case LightRGBWW:
896 msg["supported_color_modes"] = {"rgbww"};
897 break;
898 default:
899 break; // compiler shutup.
900 }
901 msg["rgb_cmd_t"] = hostName + "/" + topic + "/color/set";
902 msg["rgb_stat_t"] = "~" + topic + "/color";
903 if (strcmp(entity.effects, "")) { // Effects are defined:
904 msg["effect_command_topic"] = hostName + "/" + topic + "/effect/set";
905 msg["effect_state_topic"] = "~" + topic + "/effect";
906 // entity.effects contains a string with a comma-separated list of effect-names (e.g. "effect 1, effect2 "), make them into a JSON array:
907 JSONVar elst;
908 int ind, n;
909 n = 0;
910 String effs = entity.effects;
911 ind = effs.indexOf(',');
912 while (ind != -1) {
913 String tmp = effs.substring(0, ind);
914 tmp.trim();
915 elst[n] = tmp;
916 n += 1;
917 effs = effs.substring(ind + 1);
918 ind = effs.indexOf(',');
919 }
920 String tmp = effs;
921 tmp.trim();
922 elst[n] = tmp;
923 msg["effect_list"] = elst; // JSON array, each element contains the name of one effect.
924 }
925 }
926 flushDeviceConfig(entity.type, msg);
927 }
928
929 void publishSensorConfig(JSONVar &msg, Entity &entity, String &topic) {
930 msg["stat_t"] = "~" + topic + "/" + entity.value;
931 if (*entity.val_tpl) {
932 msg["val_tpl"] = entity.val_tpl;
933 }
934 if (*entity.unit) {
935 msg["unit_of_meas"] = entity.unit;
936 }
937 if (entity.exp_aft != -1) {
938 msg["exp_aft"] = entity.exp_aft;
939 }
940 if (entity.frc_upd) {
941 msg["frc_upd"] = "true";
942 }
943 flushDeviceConfig(entity.type, msg);
944 }
945
946 void publishSwitchConfig(JSONVar &msg, Entity &entity, String &topic) {
947 msg["stat_t"] = "~" + topic + "/state";
948 msg["cmd_t"] = hostName + "/" + topic + "/set";
949 msg["payload_on"] = "on";
950 msg["payload_off"] = "off";
951 if (*entity.dev_cla) {
952 msg["dev_cla"] = entity.dev_cla;
953 }
954 flushDeviceConfig(entity.type, msg);
955 }
956
957 void unpublishConfigs() {
958 // device config
959 pSched->publish("!homeassistant/sensor/" + deviceId + "_status/config");
960
961 // entity configs
962 for (unsigned int i = 0; i < entityConfigs.length(); i++) {
963 unpublishConfig(entityConfigs[i]);
964 }
965 }
966
967 void unpublishConfig(Entity &entity) {
968 String entityKey = getEntityKey(entity);
969 String configTopic = haTopicConfig + getDeviceClass(entity.type) + "/";
970 if (entity.channel == -1) {
971 pSched->publish(configTopic + entityKey + "/config");
972 } else if (entity.channel < -1) {
973 for (int channel = 0; channel < abs(entity.channel); channel++) {
974 pSched->publish(configTopic + entityKey + "_" + channel + "/config");
975 }
976 } else {
977 pSched->publish(configTopic + entityKey + "_" + entity.channel + "/config");
978 }
979 }
980
981 void publishAttribs() {
982 JSONVar msg = JSON.parse("{}");
983 msg["RSSI"] = String(WifiGetRssiAsQuality(rssiVal));
984 msg["Signal (dBm)"] = String(rssiVal);
985 msg["Mac"] = macAddress;
986 msg["IP"] = ipAddress;
987 msg["Host"] = hostName;
988 for (unsigned int i = 0; i < attribGroups.length(); i++) {
989 msg["Manufacturer"] = attribGroups[i].manufacturer;
990 msg["Model"] = attribGroups[i].model;
991 msg["Version"] = attribGroups[i].version;
992 pSched->publish(haTopicAttrib + attribGroups[i].name, JSON.stringify(msg));
993 }
994 }
995
996 void unpublishAttribs() {
997 for (unsigned int i = 0; i < attribGroups.length(); i++) {
998 pSched->publish(haTopicAttrib + attribGroups[i].name);
999 }
1000 }
1001
1002 void publishState() {
1003 pSched->publish("ha/state", autodiscovery ? "on" : "off");
1004 }
1005
1006 void updateHA() {
1007 if (connected) {
1008 if (autodiscovery) {
1009 publishAttribs();
1010 publishConfigs();
1011 } else {
1012 unpublishConfigs();
1013 unpublishAttribs();
1014 }
1015 }
1016 }
1017
1018 static const char *copyfieldgetnext(const char *field, String &value) {
1019 strcpy((char *)field, value.c_str());
1020 return field + value.length() + 1;
1021 }
1022
1023 static int WifiGetRssiAsQuality(int rssi) {
1024 int quality = 0;
1025
1026 if (rssi <= -100) {
1027 quality = 0;
1028 } else if (rssi >= -50) {
1029 quality = 100;
1030 } else {
1031 quality = 2 * (rssi + 100);
1032 }
1033 return quality;
1034 }
1035};
1036
1037const char *HomeAssistant::version = "0.1.0";
1038
1039} // namespace ustd
Definition: home_assistant.h:86
void addLight(String name, String human="", DeviceType type=LightDim, String icon="", String attribs="", String effects="")
Definition: home_assistant.h:377
DeviceType
HomeAssistant Device Type.
Definition: home_assistant.h:91
@ LightRGBWW
A color light with additional white component.
Definition: home_assistant.h:101
@ Switch
Sensor reporting binary states.
Definition: home_assistant.h:95
@ BinarySensor
Sensor reporting numerical or state values.
Definition: home_assistant.h:94
@ LightRGBW
A color light.
Definition: home_assistant.h:100
@ LightRGB
A light with light temperature that can be dimmed.
Definition: home_assistant.h:99
@ LightWW
A light that can be dimmed.
Definition: home_assistant.h:98
@ LightDim
A simple light that can only be switched on and off.
Definition: home_assistant.h:97
@ Light
A simple device that can only be switched on and off.
Definition: home_assistant.h:96
void addMultiSwitch(String name, int count, String human="", String dev_cla="", String icon="", String attribs="")
Definition: home_assistant.h:355
void begin(Scheduler *_pSched, bool initialAutodiscovery=false)
Definition: home_assistant.h:193
void setAutoDiscovery(bool enabled)
Definition: home_assistant.h:243
HomeAssistant(String name, String manufacturer, String model, String version)
Definition: home_assistant.h:173
void addAttributes(String attribGroup, String manufacturer="", String model="", String version="")
Definition: home_assistant.h:271
void addBinarySensor(String name, String value, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, int off_dly=-1, String attribs="")
Definition: home_assistant.h:535
void addSensor(String name, String value, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, String attribs="")
Definition: home_assistant.h:448
void addMultiBinarySensor(String name, String value, int count, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, int off_dly=-1, String attribs="")
Definition: home_assistant.h:596
void addMultiLight(String name, int count, String human="", DeviceType type=LightDim, String icon="", String attribs="")
Definition: home_assistant.h:422
void addSwitch(String name, int channel, String human="", String dev_cla="", String icon="", String attribs="")
Definition: home_assistant.h:333
void addSensor(String name, String value, int channel, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, String attribs="")
Definition: home_assistant.h:475
void addMultiSensor(String name, String value, int count, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, String attribs="")
Definition: home_assistant.h:504
void addLight(String name, int channel, String human="", DeviceType type=LightDim, String icon="", String attribs="", String effects="")
Definition: home_assistant.h:400
void addBinarySensor(String name, String value, int channel, String human="", String dev_cla="", String unit="", String icon="", String val_tpl="", int exp_aft=-1, bool frc_upd=false, int off_dly=-1, String attribs="")
Definition: home_assistant.h:564
void addSwitch(String name, String human="", String dev_cla="", String icon="", String attribs="")
Definition: home_assistant.h:313
mupplet-core GPIO Light class
Definition: mup_light.h:57
mupplet-core GPIO Switch class
Definition: mup_switch.h:136
The muwerk namespace.
Definition: home_assistant.h:10
long parseLong(String arg, long defaultVal)
Definition: mupplet_core.h:101