HLW8112 Driver for energy measurments (#1810)

* initial test driver for hlw8112

Signed-off-by: Nizam <code@maxters.net>

* restrict build to BK7231N
will stub other platforms later

Signed-off-by: Nizam <code@maxters.net>

* fix newer gcc build

Signed-off-by: Nizam <code@maxters.net>

* fix channel b stat restore
after all i still doesnt get pointer arithmetic

Signed-off-by: Nizam <code@maxters.net>

* clean up flashvar bk7231 still use emetering struct to store data

Signed-off-by: Nizam <code@maxters.net>

* fix OpenBK7231N_ALT build fail

Signed-off-by: Nizam <code@maxters.net>

* disable incomplete spi device raw access commands and ui

Signed-off-by: Nizam <code@maxters.net>

* remove mqtt hack for commands. leverage existing tasmota command framework

Signed-off-by: Nizam <code@maxters.net>

* missed flashvar restore

Signed-off-by: Nizam <code@maxters.net>

* disable hlw812 driver for upstream pr

Signed-off-by: Nizam <code@maxters.net>

---------

Signed-off-by: Nizam <code@maxters.net>
This commit is contained in:
Nizam Moidu
2025-09-30 18:34:15 +05:30
committed by GitHub
parent 8136ebe8d6
commit 4a2ae013ed
19 changed files with 1833 additions and 9 deletions

View File

@ -131,6 +131,9 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id, int ase
case HASS_PERCENT:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "number", index);
break;
case HASS_BUTTON:
sprintf(uniq_id, "%s_%s", longDeviceName, "button");
break;
default:
// TODO: USE type here as well?
// If type is not set, and we use "sensor" naming, we can easily make collision
@ -204,6 +207,9 @@ void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDe
case HUMIDITY_SENSOR:
sprintf(info->channel, "sensor/%s/config", uniq_id);
break;
case HASS_BUTTON:
sprintf(info->channel, "button/%s/config", uniq_id);
break;
default:
sprintf(info->channel, "sensor/%s/config", uniq_id);
break;
@ -563,13 +569,17 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, const char* p
case TIMESTAMP_SENSOR:
sprintf(g_hassBuffer, "Timestamp");
break;
case HASS_BUTTON:
sprintf(g_hassBuffer, "%s" , "");
break;
default:
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
break;
}
}
if (title) {
strcat(g_hassBuffer, "_");
if (type!=HASS_BUTTON) strcat(g_hassBuffer, "_");
strcat(g_hassBuffer, title);
}
cJSON_AddStringToObject(info->root, "name", g_hassBuffer);
@ -588,8 +598,13 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, const char* p
}
if (!isSensor && type != HASS_TEXTFIELD) { //Sensors (except binary_sensor) don't use payload
cJSON_AddStringToObject(info->root, "pl_on", payload_on); //payload_on
cJSON_AddStringToObject(info->root, "pl_off", payload_off); //payload_off
if(type == HASS_BUTTON) {
cJSON_AddStringToObject(info->root, "payload_press", payload_on);
}
else if(type != HASS_TEXTFIELD){
cJSON_AddStringToObject(info->root, "pl_on", payload_on); //payload_on
cJSON_AddStringToObject(info->root, "pl_off", payload_off); //payload_off
}
}
cJSON_AddStringToObject(info->root, "uniq_id", info->unique_id); //unique_id
@ -804,9 +819,23 @@ HassDeviceInfo* hass_init_energy_sensor_device_info(int index, int asensdataseti
// }
return info;
}
#endif
HassDeviceInfo* hass_init_button_device_info(char* title,char* cmd_id, char* press_payload, HASS_CATEGORY_TYPE type) {
HassDeviceInfo* info = 0;
const char* clientId = CFG_GetMQTTClientId();
info = hass_init_device_info(HASS_BUTTON, 0, press_payload, NULL, 0, title);
if (type == HASS_CATEGORY_DIAGNOSTIC){
cJSON_AddStringToObject(info->root, "entity_category", "diagnostic");
}
else {
cJSON_AddStringToObject(info->root, "entity_category", "config");
}
sprintf(g_hassBuffer, "cmnd/%s/%s", clientId, cmd_id);
cJSON_AddStringToObject(info->root, "command_topic", g_hassBuffer);
return info;
}
// generate string like "{{ float(value)*0.1|round(2) }}"
// {{ float(value)*0.1 }} for value=12 give 1.2000000000000002, using round() to limit the decimal places
// 2023 10 19 - it is not a perfect solution, it's better to use:

View File

@ -100,8 +100,13 @@ typedef enum {
HASS_SELECT,
HASS_PERCENT,
HASS_TEXTFIELD,
HASS_BUTTON,
} ENTITY_TYPE;
typedef enum {
HASS_CATEGORY_CONFIG = 0,
HASS_CATEGORY_DIAGNOSTIC = 1,
} HASS_CATEGORY_TYPE;
//unique_id is defined in hass_populate_unique_id and is based on CFG_GetDeviceName() whose size is CGF_DEVICE_NAME_SIZE.
//Sample unique_id would be deviceName_entityType_index.
//Currently supported entityType is `relay` or `light` - 5 char.
@ -147,5 +152,5 @@ const char* hass_build_discovery_json(HassDeviceInfo* info);
void hass_free_device_info(HassDeviceInfo* info);
char *hass_generate_multiplyAndRound_template(int decimalPlacesForRounding, int decimalPointOffset, int divider);
HassDeviceInfo* hass_init_textField_info(int index);
HassDeviceInfo* hass_init_button_device_info(char* title,char* cmd_id, char* press_payload, HASS_CATEGORY_TYPE type);
#endif // ENABLE_HA_DISCOVERY

View File

@ -2201,6 +2201,16 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
dev_info = hass_init_sensor_device_info(ENERGY_SENSOR, i, 3, 2, 1);
}
break;
case ChType_EnergyExport_kWh_div1000:
{
dev_info = hass_init_sensor_device_info(ENERGY_SENSOR, i, 3, 3, 1);
}
break;
case ChType_EnergyImport_kWh_div1000:
{
dev_info = hass_init_sensor_device_info(ENERGY_SENSOR, i, 3, 3, 1);
}
break;
case ChType_EnergyTotal_kWh_div1000:
{
dev_info = hass_init_sensor_device_info(ENERGY_SENSOR, i, 3, 3, 1);

View File

@ -557,6 +557,7 @@ const char* htmlPinRoleNames[] = {
"IRRecv_nPup",
"StripState",
"StripState_n",
"HLW_8112_SCSN",
"error",
"error",
"error",