diff --git a/openBeken_win32_mvsc2017.vcxproj b/openBeken_win32_mvsc2017.vcxproj index 75fab3a68..7624e724e 100644 --- a/openBeken_win32_mvsc2017.vcxproj +++ b/openBeken_win32_mvsc2017.vcxproj @@ -951,6 +951,8 @@ + + diff --git a/openBeken_win32_mvsc2017.vcxproj.filters b/openBeken_win32_mvsc2017.vcxproj.filters index 26578fcd0..6d5b03e8e 100644 --- a/openBeken_win32_mvsc2017.vcxproj.filters +++ b/openBeken_win32_mvsc2017.vcxproj.filters @@ -857,6 +857,12 @@ Simulator + + SelfTest + + + SelfTest + diff --git a/src/httpserver/hass.c b/src/httpserver/hass.c index 9a34475ec..2965a272b 100644 --- a/src/httpserver/hass.c +++ b/src/httpserver/hass.c @@ -65,9 +65,16 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) { case BATTERY_SENSOR: sprintf(uniq_id, "%s_%s_%d", longDeviceName, "battery", index); break; + case VOLTAGE_SENSOR: case BATTERY_VOLTAGE_SENSOR: sprintf(uniq_id, "%s_%s_%d", longDeviceName, "voltage", index); break; + case CURRENT_SENSOR: + sprintf(uniq_id, "%s_%s_%d", longDeviceName, "current", index); + break; + default: + sprintf(uniq_id, "%s_%s_%d", longDeviceName, "sensor", index); + break; } } @@ -95,11 +102,12 @@ void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDe case LIGHT_RGBCW: sprintf(info->channel, "light/%s/config", uniq_id); break; - case RELAY: sprintf(info->channel, "switch/%s/config", uniq_id); break; - + case BINARY_SENSOR: + sprintf(info->channel, "binary_sensor/%s/config", uniq_id); + break; case CO2_SENSOR: case TVOC_SENSOR: case POWER_SENSOR: @@ -109,9 +117,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 BINARY_SENSOR: - sprintf(info->channel, "binary_sensor/%s/config", uniq_id); + default: + sprintf(info->channel, "sensor/%s/config", uniq_id); + break; } } @@ -323,8 +331,17 @@ HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type) { /// @brief Initializes HomeAssistant binary sensor device discovery storage. /// @param index /// @return -HassDeviceInfo* hass_init_binary_sensor_device_info(int index) { - HassDeviceInfo* info = hass_init_device_info(BINARY_SENSOR, index, "1", "0"); +HassDeviceInfo* hass_init_binary_sensor_device_info(int index, bool bInverse) { + const char *payload_on; + const char *payload_off; + if (bInverse) { + payload_on = "1"; + payload_off = "0"; + } else { + payload_off = "1"; + payload_on = "0"; + } + HassDeviceInfo* info = hass_init_device_info(BINARY_SENSOR, index, payload_on, payload_off); sprintf(g_hassBuffer, "~/%i/get", index); cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer); //state_topic diff --git a/src/httpserver/hass.h b/src/httpserver/hass.h index 8891ad9f4..01bfe3115 100644 --- a/src/httpserver/hass.h +++ b/src/httpserver/hass.h @@ -84,7 +84,7 @@ void hass_print_unique_id(http_request_t* request, const char* fmt, ENTITY_TYPE HassDeviceInfo* hass_init_relay_device_info(int index, ENTITY_TYPE type); HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type); HassDeviceInfo* hass_init_power_sensor_device_info(int index); -HassDeviceInfo* hass_init_binary_sensor_device_info(int index); +HassDeviceInfo* hass_init_binary_sensor_device_info(int index, bool bInverse); HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel, int decPlaces, int decOffset); const char* hass_build_discovery_json(HassDeviceInfo* info); void hass_free_device_info(HassDeviceInfo* info); diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index 08f725266..1cd4477ec 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -1601,9 +1601,9 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) { hooks.free_fn = os_free; cJSON_InitHooks(&hooks); - if (relayCount > 0) { + //if (relayCount > 0) { for (i = 0; i < CHANNEL_MAX; i++) { - if (h_isChannelRelay(i)) { + if (h_isChannelRelay(i) || g_cfg.pins.channelTypes[i] == ChType_Toggle) { // TODO: flags are 32 bit and there are 64 max channels BIT_SET(flagsChannelPublished, i); if (CFG_HasFlag(OBK_FLAG_MQTT_HASS_ADD_RELAYS_AS_LIGHTS)) { @@ -1618,14 +1618,14 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) { discoveryQueued = true; } } - } + //} if (dInputCount > 0) { for (i = 0; i < CHANNEL_MAX; i++) { if (h_isChannelDigitalInput(i)) { // TODO: flags are 32 bit and there are 64 max channels BIT_SET(flagsChannelPublished, i); - dev_info = hass_init_binary_sensor_device_info(i); + dev_info = hass_init_binary_sensor_device_info(i, false); MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); hass_free_device_info(dev_info); dev_info = NULL; @@ -1739,7 +1739,16 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) { { case ChType_OpenClosed: { - dev_info = hass_init_binary_sensor_device_info(i); + dev_info = hass_init_binary_sensor_device_info(i, false); + MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); + hass_free_device_info(dev_info); + + discoveryQueued = true; + } + break; + case ChType_OpenClosed_Inv: + { + dev_info = hass_init_binary_sensor_device_info(i, true); MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); hass_free_device_info(dev_info); @@ -1800,6 +1809,15 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) { discoveryQueued = true; } break; + case ChType_Current_div1000: + { + dev_info = hass_init_sensor_device_info(CURRENT_SENSOR, i, 3, 3); + MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); + hass_free_device_info(dev_info); + + discoveryQueued = true; + } + break; case ChType_Power: { dev_info = hass_init_sensor_device_info(POWER_SENSOR, i, -1, -1); diff --git a/src/selftest/selftest_hass_discovery_ext.c b/src/selftest/selftest_hass_discovery_ext.c index c55fb7d99..fcfdea26e 100644 --- a/src/selftest/selftest_hass_discovery_ext.c +++ b/src/selftest/selftest_hass_discovery_ext.c @@ -61,6 +61,70 @@ void Test_HassDiscovery_Channel_Humidity() { SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/15/get"); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_cla", "measurement"); } +void Test_HassDiscovery_Channel_Current_div100() { + const char *shortName = "WinCurTest"; + const char *fullName = "Windows Fake Cur"; + const char *mqttName = "testCur"; + SIM_ClearOBK(shortName); + SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens"); + + CFG_SetShortDeviceName(shortName); + CFG_SetDeviceName(fullName); + + // in this example, i am using channel 4 + CHANNEL_SetType(4, ChType_Current_div100); + + SIM_ClearMQTTHistory(); + CMD_ExecuteCommand("scheduleHADiscovery 1", 0); + Sim_RunSeconds(5, false); + + // OBK device should publish JSON on MQTT topic "homeassistant" + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); + //SELFTEST_ASSERT_JSON_VALUE_STRING(0, "name", "WinCurTest Current"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "current"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "A"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "val_tpl", "{{ float(value)*0.01|round(3) }}"); + // in this example, i am using channel 4 + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/4/get"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_cla", "measurement"); +} +void Test_HassDiscovery_Channel_Current_div1000() { + const char *shortName = "WinCurTest"; + const char *fullName = "Windows Fake Cur"; + const char *mqttName = "testCur"; + SIM_ClearOBK(shortName); + SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens"); + + CFG_SetShortDeviceName(shortName); + CFG_SetDeviceName(fullName); + + // in this example, i am using channel 14 + CHANNEL_SetType(14, ChType_Current_div1000); + + SIM_ClearMQTTHistory(); + CMD_ExecuteCommand("scheduleHADiscovery 1", 0); + Sim_RunSeconds(5, false); + + // OBK device should publish JSON on MQTT topic "homeassistant" + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); + //SELFTEST_ASSERT_JSON_VALUE_STRING(0, "name", "WinCurTest Current"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "current"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "A"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "val_tpl", "{{ float(value)*0.001|round(3) }}"); + // in this example, i am using channel 14 + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/14/get"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_cla", "measurement"); +} void Test_HassDiscovery_Channel_Voltage_div10() { const char *shortName = "WinVolTest"; const char *fullName = "Windows Fake Vol"; @@ -86,7 +150,7 @@ void Test_HassDiscovery_Channel_Voltage_div10() { SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "name", "WinVolTest Voltage"); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); - SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "voltge"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "voltage"); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "V"); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "val_tpl", "{{ float(value)*0.1|round(2) }}"); // in this example, i am using channel 23 @@ -122,11 +186,109 @@ void Test_HassDiscovery_Channel_Temperature() { SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/0/get"); SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_cla", "measurement"); } +void Test_HassDiscovery_Channel_Temperature_div10() { + const char *shortName = "WinTempTest"; + const char *fullName = "Windows Fake Temp"; + const char *mqttName = "testTemp"; + SIM_ClearOBK(shortName); + SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens"); + + CFG_SetShortDeviceName(shortName); + CFG_SetDeviceName(fullName); + + CHANNEL_SetType(3, ChType_Temperature_div10); + + SIM_ClearMQTTHistory(); + CMD_ExecuteCommand("scheduleHADiscovery 1", 0); + Sim_RunSeconds(5, false); + + // OBK device should publish JSON on MQTT topic "homeassistant" + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "name", "WinTempTest Temperature"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "temperature"); + //SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "C"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/3/get"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "val_tpl", "{{ float(value)*0.1|round(2) }}"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_cla", "measurement"); +} +void Test_HassDiscovery_Channel_Toggle() { + const char *shortName = "WinToggleTest"; + const char *fullName = "Windows Fake Toggle"; + const char *mqttName = "testToggle"; + SIM_ClearOBK(shortName); + SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens"); + + CFG_SetShortDeviceName(shortName); + CFG_SetDeviceName(fullName); + + CHANNEL_SetType(4, ChType_Toggle); + + SIM_ClearMQTTHistory(); + CMD_ExecuteCommand("scheduleHADiscovery 1", 0); + Sim_RunSeconds(5, false); + + // OBK device should publish JSON on MQTT topic "homeassistant" + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); + //SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "C"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/4/get"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "cmd_t", "~/4/set"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "pl_on", "1"); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "pl_off", "0"); +} +void Test_HassDiscovery_Channel_Toggle_2x() { + const char *shortName = "WinToggleTest"; + const char *fullName = "Windows Fake Toggle"; + const char *mqttName = "testToggle"; + SIM_ClearOBK(shortName); + SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens"); + + CFG_SetShortDeviceName(shortName); + CFG_SetDeviceName(fullName); + + CHANNEL_SetType(4, ChType_Toggle); + CHANNEL_SetType(5, ChType_Toggle); + + SIM_ClearMQTTHistory(); + CMD_ExecuteCommand("scheduleHADiscovery 1", 0); + Sim_RunSeconds(5, false); + + // OBK device should publish JSON on MQTT topic "homeassistant" + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER); + SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME); + SELFTEST_ASSERT_JSON_VALUE_STRING(0, "~", mqttName); + //SELFTEST_ASSERT_JSON_VALUE_STRING(0, "unit_of_meas", "C"); + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "pl_on", "1"); + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "pl_off", "0"); + // we have used channel index 4 + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "stat_t", "~/4/get"); + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "cmd_t", "~/4/set"); + // AND we have used channel index 5 + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "stat_t", "~/5/get"); + SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY("homeassistant", true, 0, 0, "cmd_t", "~/5/set"); +} void Test_HassDiscovery_Ext() { Test_HassDiscovery_TuyaMCU_VoltageCurrentPower(); Test_HassDiscovery_Channel_Humidity(); Test_HassDiscovery_Channel_Temperature(); + Test_HassDiscovery_Channel_Temperature_div10(); Test_HassDiscovery_Channel_Voltage_div10(); + Test_HassDiscovery_Channel_Current_div100(); + Test_HassDiscovery_Channel_Current_div1000(); + Test_HassDiscovery_Channel_Toggle(); + Test_HassDiscovery_Channel_Toggle_2x(); }