HA configuration

This commit is contained in:
Gunnar Skjold 2023-03-30 14:54:10 +02:00
parent 0d8c88b1fc
commit 1e7176af0b
12 changed files with 246 additions and 54 deletions

View File

@ -21,6 +21,7 @@
#define CONFIG_DOMOTICZ_START 856
#define CONFIG_NTP_START 872
#define CONFIG_MQTT_START 1004
#define CONFIG_HA_START 1680
#define CONFIG_METER_START_93 224
@ -151,6 +152,13 @@ struct DomoticzConfig {
uint16_t cl1idx;
}; // 10
struct HomeAssistantConfig {
uint8_t tag; // Just to find out if we have this config already. Can be removed in v2.3
char discoveryTopic[64];
char discoveryHostname[64];
char discoveryNameTag[16];
}; // 145
struct NtpConfig {
bool enable;
bool dhcp;
@ -253,8 +261,10 @@ public:
bool getDomoticzConfig(DomoticzConfig&);
bool setDomoticzConfig(DomoticzConfig&);
void clearDomo(DomoticzConfig&);
bool isDomoChanged();
void ackDomoChange();
bool getHomeAssistantConfig(HomeAssistantConfig&);
bool setHomeAssistantConfig(HomeAssistantConfig&);
void clearHomeAssistantConfig(HomeAssistantConfig&);
bool getNtpConfig(NtpConfig&);
bool setNtpConfig(NtpConfig&);
@ -293,7 +303,7 @@ protected:
private:
uint8_t configVersion = 0;
bool wifiChanged, mqttChanged, meterChanged = true, domoChanged, ntpChanged = true, entsoeChanged = false, energyAccountingChanged = true;
bool wifiChanged, mqttChanged, meterChanged = true, ntpChanged = true, entsoeChanged = false, energyAccountingChanged = true;
uint8_t tempSensorCount = 0;
TempSensorConfig** tempSensors = NULL;
@ -310,3 +320,4 @@ private:
void deleteFromFs(uint8_t version);
};
#endif

View File

@ -309,15 +309,14 @@ bool AmsConfiguration::getDomoticzConfig(DomoticzConfig& config) {
bool AmsConfiguration::setDomoticzConfig(DomoticzConfig& config) {
DomoticzConfig existing;
if(getDomoticzConfig(existing)) {
domoChanged |= config.elidx != existing.elidx;
domoChanged |= config.vl1idx != existing.vl1idx;
domoChanged |= config.vl2idx != existing.vl2idx;
domoChanged |= config.vl3idx != existing.vl3idx;
domoChanged |= config.cl1idx != existing.cl1idx;
mqttChanged |= config.elidx != existing.elidx;
mqttChanged |= config.vl1idx != existing.vl1idx;
mqttChanged |= config.vl2idx != existing.vl2idx;
mqttChanged |= config.vl3idx != existing.vl3idx;
mqttChanged |= config.cl1idx != existing.cl1idx;
} else {
domoChanged = true;
mqttChanged = true;
}
mqttChanged = domoChanged;
EEPROM.begin(EEPROM_SIZE);
EEPROM.put(CONFIG_DOMOTICZ_START, config);
bool ret = EEPROM.commit();
@ -333,12 +332,45 @@ void AmsConfiguration::clearDomo(DomoticzConfig& config) {
config.cl1idx = 0;
}
bool AmsConfiguration::isDomoChanged() {
return domoChanged;
bool AmsConfiguration::getHomeAssistantConfig(HomeAssistantConfig& config) {
if(hasConfig()) {
EEPROM.begin(EEPROM_SIZE);
EEPROM.get(CONFIG_HA_START, config);
if(config.tag != 0xA7) clearHomeAssistantConfig(config);
EEPROM.end();
return true;
} else {
clearHomeAssistantConfig(config);
return false;
}
}
void AmsConfiguration::ackDomoChange() {
domoChanged = false;
bool AmsConfiguration::setHomeAssistantConfig(HomeAssistantConfig& config) {
HomeAssistantConfig existing;
if(getHomeAssistantConfig(existing)) {
mqttChanged |= strcmp(config.discoveryTopic, existing.discoveryTopic) != 0;
mqttChanged |= strcmp(config.discoveryHostname, existing.discoveryHostname) != 0;
mqttChanged |= strcmp(config.discoveryNameTag, existing.discoveryNameTag) != 0;
} else {
mqttChanged = true;
}
stripNonAscii((uint8_t*) config.discoveryTopic, 64);
stripNonAscii((uint8_t*) config.discoveryHostname, 64);
stripNonAscii((uint8_t*) config.discoveryNameTag, 16);
EEPROM.begin(EEPROM_SIZE);
EEPROM.put(CONFIG_HA_START, config);
bool ret = EEPROM.commit();
EEPROM.end();
return ret;
}
void AmsConfiguration::clearHomeAssistantConfig(HomeAssistantConfig& config) {
config.tag = 0xA7;
strcpy(config.discoveryTopic, "");
strcpy(config.discoveryHostname, "");
strcpy(config.discoveryNameTag, "");
}
bool AmsConfiguration::pinUsed(uint8_t pin, GpioConfig& config) {

View File

@ -3,14 +3,51 @@
#include "AmsMqttHandler.h"
#include "HomeAssistantStatic.h"
#include "AmsConfiguration.h"
class HomeAssistantMqttHandler : public AmsMqttHandler {
public:
HomeAssistantMqttHandler(MQTTClient* mqtt, char* buf, const char* clientId, const char* topic, HwTools* hw) : AmsMqttHandler(mqtt, buf) {
HomeAssistantMqttHandler(MQTTClient* mqtt, char* buf, const char* clientId, const char* topic, uint8_t boardType, HomeAssistantConfig config, HwTools* hw) : AmsMqttHandler(mqtt, buf) {
this->clientId = clientId;
this->topic = String(topic);
this->config = config;
this->hw = hw;
l1Init = l2Init = l2eInit = l3Init = l3eInit = l4Init = l4eInit = rtInit = rteInit = pInit = sInit = false;
if(strlen(config.discoveryNameTag) > 0) {
snprintf_P(buf, 128, PSTR("AMS reader (%s)"), config.discoveryNameTag);
deviceName = String(buf);
snprintf_P(buf, 128, PSTR(" (%s)"), config.discoveryNameTag);
sensorNamePostFix = String(buf);
} else {
deviceName = "AMS reader";
sensorNamePostFix = "";
}
deviceModel = boardTypeToString(boardType);
manufacturer = boardManufacturerToString(boardType);
#if defined(ESP8266)
String hostname = WiFi.hostname();
#elif defined(ESP32)
String hostname = WiFi.getHostname();
#endif
deviceUid = hostname; // Maybe configurable in the future?
if(strlen(config.discoveryHostname) > 0) {
snprintf_P(buf, 128, PSTR("http://%s.local/"), config.discoveryHostname);
String deviceUrl = String(buf);
} else {
snprintf_P(buf, 128, PSTR("http://%s.local/"), hostname);
String deviceUrl = String(buf);
}
if(strlen(config.discoveryTopic) > 0) {
discoveryTopic = String(config.discoveryTopic);
if(!discoveryTopic.endsWith("/")) discoveryTopic += "/";
} else {
discoveryTopic = "homeassistant/sensor/";
}
};
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi);
bool publishTemperatures(AmsConfiguration*, HwTools*);
@ -33,15 +70,15 @@ public:
void publishSystemSensors();
private:
String haTopic = "homeassistant/sensor/";
HomeAssistantConfig config;
String deviceName;
String deviceModel;
String deviceUid;
String manufacturer;
String deviceUrl;
String haName = "AMS reader";
#if defined(ESP32)
String haModel = "ESP32";
#elif defined(ESP8266)
String haModel = "ESP8266";
#endif
String haManuf = "AmsToMqttBridge";
String discoveryTopic;
String sensorNamePostFix;
bool l1Init, l2Init, l2eInit, l3Init, l3eInit, l4Init, l4eInit, rtInit, rteInit, pInit, sInit;
bool tInit[32] = {false};
@ -50,5 +87,75 @@ private:
String clientId;
String topic;
HwTools* hw;
String boardTypeToString(uint8_t b) {
switch(b) {
case 5:
#if defined(ESP8266)
return "Pow-K";
#elif defined(ESP32)
return "Pow-K+";
#endif
case 7:
#if defined(ESP8266)
return "Pow-U";
#elif defined(ESP32)
return "Pow-U+";
#endif
case 6:
return "Pow-P1";
case 51:
return "S2 mini";
case 50:
return "ESP32-S2";
case 201:
return "LOLIN D32";
case 202:
return "HUZZAH32";
case 203:
return "DevKitC";
case 200:
return "ESP32";
case 2:
return "HAN Reader 2.0 by Max Spencer";
case 0:
return "Custom hardware by Roar Fredriksen";
case 1:
return "Kamstrup module by Egil Opsahl";
case 3:
return "Pow-K";
case 4:
return "Pow-U";
case 101:
return "D1 mini";
case 100:
return "ESP8266";
case 70:
return "ESP32-C3";
case 71:
return "ESP32-C3-DevKitM-1";
}
#if defined(ESP8266)
return "ESP8266";
#elif defined(ESP32)
return "ESP32";
#endif
};
String boardManufacturerToString(uint8_t b) {
if(b >= 3 && b <= 7)
return "amsleser.no";
if(b < 50)
return "Custom";
switch(b) {
case 51:
case 101:
case 201:
return "Wemos";
case 202:
return "Adafruit";
}
return "Espressif";
};
};
#endif

View File

@ -1,5 +1,5 @@
{
"name" : "%s",
"name" : "%s%s",
"stat_t" : "%s%s",
"uniq_id" : "%s_%s",
"obj_id" : "%s_%s",

View File

@ -304,37 +304,30 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
}
void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) {
#if defined(ESP8266)
String haUID = WiFi.hostname();
#elif defined(ESP32)
String haUID = WiFi.getHostname();
#endif
String haUrl = "http://" + haUID + ".local/";
String uid = String(sensor.path);
uid.replace(".", "");
uid.replace("[", "");
uid.replace("]", "");
uid.replace("'", "");
String uom = String(sensor.uom);
snprintf_P(json, BufferSize, HADISCOVER_JSON,
sensor.name,
sensorNamePostFix.c_str(),
topic.c_str(), sensor.topic,
haUID.c_str(), uid.c_str(),
haUID.c_str(), uid.c_str(),
uom.c_str(),
deviceUid.c_str(), uid.c_str(),
deviceUid.c_str(), uid.c_str(),
sensor.uom,
sensor.path,
sensor.devcl,
haUID.c_str(),
haName.c_str(),
haModel.c_str(),
deviceUid.c_str(),
deviceName.c_str(),
deviceModel.c_str(),
VERSION,
haManuf.c_str(),
haUrl.c_str(),
manufacturer.c_str(),
sensorNamePostFix.c_str(),
strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "",
strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : ""
);
mqtt->publish(haTopic + haUID + "_" + uid.c_str() + "/config", json, true, 0);
mqtt->publish(discoveryTopic + deviceUid + "_" + uid.c_str() + "/config", json, true, 0);
}
void HomeAssistantMqttHandler::publishList1Sensors() {

File diff suppressed because one or more lines are too long

View File

@ -93,6 +93,9 @@
r: { r: null, g: null, b: null, i: false },
t: { d: null, a: null },
v: { p: null, d: { v: null, g: null }, o: null, m: null, b: null }
},
h: {
t: '', h: '', n: ''
}
};
configurationStore.subscribe(update => {
@ -531,6 +534,25 @@
</div>
</div>
{/if}
{#if configuration.q.m == 4}
<div class="cnt">
<strong class="text-sm">Home-Assistant</strong>
<a href="{wiki('MQTT-configuration#home-assistant')}" target="_blank" class="float-right"><HelpIcon/></a>
<input type="hidden" name="h" value="true"/>
<div class="my-1">
Discovery topic<br/>
<input name="ht" bind:value={configuration.h.t} type="text" class="in-s" placeholder="homeassistant/sensor"/>
</div>
<div class="my-1">
Hostname for URL<br/>
<input name="hh" bind:value={configuration.h.h} type="text" class="in-s" placeholder="{configuration.g.h}.local"/>
</div>
<div class="my-1">
Name tag<br/>
<input name="hn" bind:value={configuration.h.n} type="text" class="in-s"/>
</div>
</div>
{/if}
{#if configuration.p.r.startsWith("10YNO") || configuration.p.r == '10Y1001A1001A48H'}
<div class="cnt">
<strong class="text-sm">Tariff thresholds</strong>

View File

@ -86,7 +86,7 @@ export function boardtype(c, b) {
case 0:
return "Custom hardware by Roar Fredriksen";
case 1:
return "Kamstrup module by Egil Opsahl"
return "Kamstrup module by Egil Opsahl";
case 3:
return "Pow-K (UART0)";
case 4:

View File

@ -4,4 +4,4 @@
"u1" : %d,
"u2" : %d,
"u3" : %d
}
},

View File

@ -0,0 +1,5 @@
"h": {
"t" : "%s",
"h" : "%s",
"n" : "%s"
}

View File

@ -27,6 +27,7 @@
#include "html/conf_debug_json.h"
#include "html/conf_gpio_json.h"
#include "html/conf_domoticz_json.h"
#include "html/conf_ha_json.h"
#include "html/conf_ui_json.h"
#include "html/firmware_html.h"
@ -800,6 +801,8 @@ void AmsWebServer::configurationJson() {
config->getDomoticzConfig(domo);
UiConfig ui;
config->getUiConfig(ui);
HomeAssistantConfig haconf;
config->getHomeAssistantConfig(haconf);
bool qsc = false;
bool qsr = false;
@ -949,6 +952,12 @@ void AmsWebServer::configurationJson() {
domo.vl3idx
);
server.sendContent(buf);
snprintf_P(buf, BufferSize, CONF_HA_JSON,
haconf.discoveryTopic,
haconf.discoveryHostname,
haconf.discoveryNameTag
);
server.sendContent(buf);
server.sendContent("}");
}
@ -1278,6 +1287,15 @@ void AmsWebServer::handleSave() {
config->setDomoticzConfig(domo);
}
if(server.hasArg(F("h")) && server.arg(F("h")) == F("true")) {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Home-Assistant config"));
HomeAssistantConfig haconf;
config->getHomeAssistantConfig(haconf);
strcpy(haconf.discoveryTopic, server.arg(F("ht")).c_str());
strcpy(haconf.discoveryHostname, server.arg(F("hh")).c_str());
strcpy(haconf.discoveryNameTag, server.arg(F("hn")).c_str());
config->setHomeAssistantConfig(haconf);
}
if(server.hasArg(F("g")) && server.arg(F("g")) == F("true")) {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received web config"));

View File

@ -1361,7 +1361,11 @@ void MQTT_connect() {
mqttHandler = new DomoticzMqttHandler(mqtt, (char*) commonBuffer, domo);
break;
case 4:
mqttHandler = new HomeAssistantMqttHandler(mqtt, (char*) commonBuffer, mqttConfig.clientId, mqttConfig.publishTopic, &hw);
HomeAssistantConfig haconf;
SystemConfig sys;
config.getHomeAssistantConfig(haconf);
config.getSystemConfig(sys);
mqttHandler = new HomeAssistantMqttHandler(mqtt, (char*) commonBuffer, mqttConfig.clientId, mqttConfig.publishTopic, sys.boardType, haconf, &hw);
break;
}