mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-13 15:37:03 +00:00
HA configuration
This commit is contained in:
parent
0d8c88b1fc
commit
1e7176af0b
@ -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
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name" : "%s",
|
||||
"name" : "%s%s",
|
||||
"stat_t" : "%s%s",
|
||||
"uniq_id" : "%s_%s",
|
||||
"obj_id" : "%s_%s",
|
||||
|
||||
@ -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() {
|
||||
|
||||
20
lib/SvelteUi/app/dist/index.js
vendored
20
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@ -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>
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -4,4 +4,4 @@
|
||||
"u1" : %d,
|
||||
"u2" : %d,
|
||||
"u3" : %d
|
||||
}
|
||||
},
|
||||
|
||||
5
lib/SvelteUi/json/conf_ha.json
Normal file
5
lib/SvelteUi/json/conf_ha.json
Normal file
@ -0,0 +1,5 @@
|
||||
"h": {
|
||||
"t" : "%s",
|
||||
"h" : "%s",
|
||||
"n" : "%s"
|
||||
}
|
||||
@ -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"));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user