From f7a9e9ece455e4174a939595d407cfbd361d2113 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 18 Sep 2024 22:00:08 -0700 Subject: [PATCH] Add support for VSENSOR in MQTT Client. New commands: - SYS:MQTT:INT:VSENSOR - SYS:MQTT:INT:VSENSOR? - SYS:MQTT:MASK:VTEMP - SYS:MQTT:MASK:VTEMP? - SYS:MQTT:MASK:VHUM - SYS:MQTT:MASK:VHUM? - SYS:MQTT:MASK:VPRE - SYS:MQTT:MASK:VPRE? - SYS:MQTT:TOPIC:VTEMP - SYS:MQTT:TOPIC:VTEMP? - SYS:MQTT:TOPIC:VHUM - SYS:MQTT:TOPIC:VHUM? - SYS:MQTT:TOPIC:VPRE - SYS:MQTT:TOPIC:VPRE? --- commands.md | 186 +++++++++++++++++++++++++++++++++++++++++++++++++- src/command.c | 55 +++++++++++++++ src/config.c | 61 +++++++++++++++++ src/fanpico.h | 8 +++ src/mqtt.c | 84 +++++++++++++++++++++++ src/network.c | 6 ++ 6 files changed, 399 insertions(+), 1 deletion(-) diff --git a/commands.md b/commands.md index 5429632..d247488 100644 --- a/commands.md +++ b/commands.md @@ -145,12 +145,20 @@ Fanpico supports following commands: * [SYStem:MQTT:INTerval:STATUS?](#systemmqttintervalstatus-1) * [SYStem:MQTT:INTerval:TEMP](#systemmqttintervaltemp) * [SYStem:MQTT:INTerval:TEMP?](#systemmqttintervaltemp-1) +* [SYStem:MQTT:INTerval:VSENsor](#systemmqttintervalvsensor) +* [SYStem:MQTT:INTerval:VSENsor?](#systemmqttintervalvsensor-1) * [SYStem:MQTT:INTerval:RPM](#systemmqttintervalrpm) * [SYStem:MQTT:INTerval:RPM?](#systemmqttintervalrpm-1) * [SYStem:MQTT:INTerval:PWM](#systemmqttintervalpwm) * [SYStem:MQTT:INTerval:PWM?](#systemmqttintervalpwm-1) * [SYStem:MQTT:MASK:TEMP](#systemmqttmasktemp) * [SYStem:MQTT:MASK:TEMP?](#systemmqttmasktemp-1) +* [SYStem:MQTT:MASK:VTEMP](#systemmqttmaskvtemp) +* [SYStem:MQTT:MASK:VTEMP?](#systemmqttmaskvtemp-1) +* [SYStem:MQTT:MASK:VHUMidity](#systemmqttmaskvhumidity) +* [SYStem:MQTT:MASK:VHUMidity?](#systemmqttmaskvhumidity-1) +* [SYStem:MQTT:MASK:VPREssure](#systemmqttmaskvpressure) +* [SYStem:MQTT:MASK:VPREssure?](#systemmqttmaskvpressure-1) * [SYStem:MQTT:MASK:FANRPM](#systemmqttmaskfanrpm) * [SYStem:MQTT:MASK:FANRPM?](#systemmqttmaskfanrpm-1) * [SYStem:MQTT:MASK:FANPWM](#systemmqttmaskfanpwm) @@ -167,6 +175,12 @@ Fanpico supports following commands: * [SYStem:MQTT:TOPIC:RESPonse?](#systemmqttopicresponse-1) * [SYStem:MQTT:TOPIC:TEMP](#systemmqtttopictemp) * [SYStem:MQTT:TOPIC:TEMP?](#systemmqttopictemp-1) +* [SYStem:MQTT:TOPIC:VTEMP](#systemmqtttopicvtemp) +* [SYStem:MQTT:TOPIC:VTEMP?](#systemmqttopicvtemp-1) +* [SYStem:MQTT:TOPIC:VHUMidity](#systemmqtttopicvhumidity) +* [SYStem:MQTT:TOPIC:VHUMidity?](#systemmqttopicvhumidity-1) +* [SYStem:MQTT:TOPIC:VPREssure](#systemmqtttopicvpressure) +* [SYStem:MQTT:TOPIC:VPREssure?](#systemmqttopicvpressure-1) * [SYStem:MQTT:TOPIC:FANRPM](#systemmqtttopicfanrpm) * [SYStem:MQTT:TOPIC:FANRPM?](#systemmqttopicfanrpm-1) * [SYStem:MQTT:TOPIC:FANPWM](#systemmqtttopicfanpwm) @@ -2254,6 +2268,29 @@ SYS:MQTT:INT:TEMP? ``` +#### SYStem:MQTT:INTerval:VSENsor +Configure how often unit will publish (send) virtual sensor status messages. +Set this to 0 (seconds) to disable publishing status updates. +Recommended values are 60 (seconds) or higher. + +Default: 0 (disabled) + +Example: +``` +SYS:MQTT:INT:VSEN 60 +``` + + +#### SYStem:MQTT:INTerval:VSENsor? +Query how often unit is setup to publish virtual sensor status messages. + +Example: +``` +SYS:MQTT:INT:VSENP? +60 +``` + + #### SYStem:MQTT:INTerval:RPM Configure how often unit will publish (send) RPM status updates for fans (and mbfans). @@ -2328,6 +2365,78 @@ SYS:MQTT:MASK:TEMP? ``` +#### SYStem:MQTT:MASK:VTEMP +Configure which virtual sensors should publish (send) temperature data to MQTT server. + +Sensors can be specified as comma separated list (2,3) or as range (1-3) +or as combination of both. + +Default: (do not publish data from any sensor) + +Example: +``` +SYS:MQTT:MASK:VTEMP 1,2,3,4 +``` + + +#### SYStem:MQTT:MASK:VTEMP? +Query which virtual sensors are configured to publish (send) temperature data to MQTT server. + +Example: +``` +SYS:MQTT:MASK:VTEMP? +1-4 +``` + + +#### SYStem:MQTT:MASK:VHUMidity +Configure which virtual sensors should publish (send) humidity data to MQTT server. + +Sensors can be specified as comma separated list (2,3) or as range (1-3) +or as combination of both. + +Default: (do not publish data from any sensor) + +Example: +``` +SYS:MQTT:MASK:VHUM 1,2 +``` + + +#### SYStem:MQTT:MASK:VHUMidity? +Query which virtual sensors are configured to publish (send) humidity data to MQTT server. + +Example: +``` +SYS:MQTT:MASK:VHUM? +1-2 +``` + + +#### SYStem:MQTT:MASK:VPREssure +Configure which virtual sensors should publish (send) pressure data to MQTT server. + +Sensors can be specified as comma separated list (2,3) or as range (1-3) +or as combination of both. + +Default: (do not publish data from any sensor) + +Example: +``` +SYS:MQTT:MASK:VPRE 1,2 +``` + + +#### SYStem:MQTT:MASK:VPREssure? +Query which virtual sensors are configured to publish (send) pressure data to MQTT server. + +Example: +``` +SYS:MQTT:MASK:VPRE? +1-2 +``` + + #### SYStem:MQTT:MASK:FANRPM Configure which fan ports should publish (send) RPM data to MQTT server. @@ -2502,7 +2611,7 @@ Default: Example: ``` -SYS:MQTT:TOPIC:TEMP musername/feeds/temp%d +SYS:MQTT:TOPIC:TEMP mysername/feeds/temp%d ``` @@ -2516,6 +2625,81 @@ myusername/feeds/temp%d ``` +#### SYStem:MQTT:TOPIC:VTEMP +Configure topic template for publishing virtual sensor temperature data to. +If this is left to empty, then unit won't send response to any commands. + +This is template string where ```%d``` should be used to mark the port number. + + +Default: + +Example: +``` +SYS:MQTT:TOPIC:VTEMP mysername/feeds/vtemp%d +``` + + +#### SYStem:MQTT:TOPIC:VTEMP? +Query currently set topic template for virtual sensor temperature data. + +Example: +``` +SYS:MQTT:TOPIC:VTEMP? +myusername/feeds/vtemp%d +``` + + +#### SYStem:MQTT:TOPIC:VHUMidity +Configure topic template for publishing virtual sensor humidity data to. +If this is left to empty, then unit won't send response to any commands. + +This is template string where ```%d``` should be used to mark the port number. + + +Default: + +Example: +``` +SYS:MQTT:TOPIC:VHUM mysername/feeds/humidity%d +``` + + +#### SYStem:MQTT:TOPIC:VHUMidity? +Query currently set topic template for virtual sensor humidity data. + +Example: +``` +SYS:MQTT:TOPIC:VHUM? +myusername/feeds/humidity%d +``` + + +#### SYStem:MQTT:TOPIC:VPREssure +Configure topic template for publishing virtual sensor pressure data to. +If this is left to empty, then unit won't send response to any commands. + +This is template string where ```%d``` should be used to mark the port number. + + +Default: + +Example: +``` +SYS:MQTT:TOPIC:VPRE mysername/feeds/pressure%d +``` + + +#### SYStem:MQTT:TOPIC:VPREssure? +Query currently set topic template for virtual sensor pressure data. + +Example: +``` +SYS:MQTT:TOPIC:VPRE? +myusername/feeds/pressure%d +``` + + #### SYStem:MQTT:TOPIC:FANRPM Configure topic template for publishing fan RPM data to. If this is left to empty, then unit won't send response to any commands. diff --git a/src/command.c b/src/command.c index dbd7320..521e40d 100644 --- a/src/command.c +++ b/src/command.c @@ -2275,6 +2275,12 @@ int cmd_mqtt_temp_interval(const char *cmd, const char *args, int query, struct &conf->mqtt_temp_interval, 0, (86400 * 30), "MQTT Publish Temp Interval"); } +int cmd_mqtt_vsensor_interval(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return uint32_setting(cmd, args, query, prev_cmd, + &conf->mqtt_vsensor_interval, 0, (86400 * 30), "MQTT Publish VSENSOR Interval"); +} + int cmd_mqtt_rpm_interval(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) { return uint32_setting(cmd, args, query, prev_cmd, @@ -2321,6 +2327,27 @@ int cmd_mqtt_temp_topic(const char *cmd, const char *args, int query, struct pre sizeof(conf->mqtt_temp_topic), "MQTT Temperature Topic", NULL); } +int cmd_mqtt_vtemp_topic(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return string_setting(cmd, args, query, prev_cmd, + conf->mqtt_vtemp_topic, + sizeof(conf->mqtt_vtemp_topic), "MQTT VTemperature Topic", NULL); +} + +int cmd_mqtt_vhumidity_topic(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return string_setting(cmd, args, query, prev_cmd, + conf->mqtt_vhumidity_topic, + sizeof(conf->mqtt_vhumidity_topic), "MQTT VHumidity Topic", NULL); +} + +int cmd_mqtt_vpressure_topic(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return string_setting(cmd, args, query, prev_cmd, + conf->mqtt_vpressure_topic, + sizeof(conf->mqtt_vpressure_topic), "MQTT VPressure Topic", NULL); +} + int cmd_mqtt_fan_rpm_topic(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) { return string_setting(cmd, args, query, prev_cmd, @@ -2363,6 +2390,27 @@ int cmd_mqtt_mask_temp(const char *cmd, const char *args, int query, struct prev 1, "MQTT Temperature Mask"); } +int cmd_mqtt_mask_vtemp(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return bitmask16_setting(cmd, args, query, prev_cmd, + &conf->mqtt_vtemp_mask, VSENSOR_MAX_COUNT, + 1, "MQTT VSENSOR Temperature Mask"); +} + +int cmd_mqtt_mask_vhumidity(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return bitmask16_setting(cmd, args, query, prev_cmd, + &conf->mqtt_vhumidity_mask, VSENSOR_MAX_COUNT, + 1, "MQTT VSENSOR Humidity Mask"); +} + +int cmd_mqtt_mask_vpressure(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) +{ + return bitmask16_setting(cmd, args, query, prev_cmd, + &conf->mqtt_vpressure_mask, VSENSOR_MAX_COUNT, + 1, "MQTT VSENSOR Pressure Mask"); +} + int cmd_mqtt_mask_fan_rpm(const char *cmd, const char *args, int query, struct prev_cmd_t *prev_cmd) { return bitmask16_setting(cmd, args, query, prev_cmd, @@ -2864,6 +2912,9 @@ const struct cmd_t wifi_commands[] = { #ifdef WIFI_SUPPORT const struct cmd_t mqtt_mask_commands[] = { { "TEMP", 4, NULL, cmd_mqtt_mask_temp }, + { "VTEMP", 5, NULL, cmd_mqtt_mask_vtemp }, + { "VHUMidity", 4, NULL, cmd_mqtt_mask_vhumidity }, + { "VPREssure", 4, NULL, cmd_mqtt_mask_vpressure }, { "FANRPM", 6, NULL, cmd_mqtt_mask_fan_rpm }, { "FANPWM", 6, NULL, cmd_mqtt_mask_fan_duty }, { "MBFANRPM", 8, NULL, cmd_mqtt_mask_mbfan_rpm }, @@ -2874,6 +2925,7 @@ const struct cmd_t mqtt_mask_commands[] = { const struct cmd_t mqtt_interval_commands[] = { { "STATUS", 6, NULL, cmd_mqtt_status_interval }, { "TEMP", 4, NULL, cmd_mqtt_temp_interval }, + { "VSENsor", 4, NULL, cmd_mqtt_vsensor_interval }, { "RPM", 3, NULL, cmd_mqtt_rpm_interval }, { "PWM", 3, NULL, cmd_mqtt_duty_interval }, { 0, 0, 0, 0 } @@ -2884,6 +2936,9 @@ const struct cmd_t mqtt_topic_commands[] = { { "COMMand", 4, NULL, cmd_mqtt_cmd_topic }, { "RESPonse", 4, NULL, cmd_mqtt_resp_topic }, { "TEMP", 4, NULL, cmd_mqtt_temp_topic }, + { "VTEMP", 5, NULL, cmd_mqtt_vtemp_topic }, + { "VHUMidity", 4, NULL, cmd_mqtt_vhumidity_topic }, + { "VPREssure", 4, NULL, cmd_mqtt_vpressure_topic }, { "FANRPM", 6, NULL, cmd_mqtt_fan_rpm_topic }, { "FANPWM", 6, NULL, cmd_mqtt_fan_duty_topic }, { "MBFANRPM", 8, NULL, cmd_mqtt_mbfan_rpm_topic }, diff --git a/src/config.c b/src/config.c index 456f0ff..40e6504 100644 --- a/src/config.c +++ b/src/config.c @@ -555,17 +555,24 @@ void clear_config(struct fanpico_config *cfg) cfg->mqtt_cmd_topic[0] = 0; cfg->mqtt_resp_topic[0] = 0; cfg->mqtt_temp_mask = 0; + cfg->mqtt_vtemp_mask = 0; + cfg->mqtt_vhumidity_mask = 0; + cfg->mqtt_vpressure_mask = 0; cfg->mqtt_fan_rpm_mask = 0; cfg->mqtt_fan_duty_mask = 0; cfg->mqtt_mbfan_rpm_mask = 0; cfg->mqtt_mbfan_duty_mask = 0; cfg->mqtt_temp_topic[0] = 0; + cfg->mqtt_vtemp_topic[0] = 0; + cfg->mqtt_vhumidity_topic[0] = 0; + cfg->mqtt_vpressure_topic[0] = 0; cfg->mqtt_fan_rpm_topic[0] = 0; cfg->mqtt_fan_duty_topic[0] = 0; cfg->mqtt_mbfan_rpm_topic[0] = 0; cfg->mqtt_mbfan_duty_topic[0] = 0; cfg->mqtt_status_interval = DEFAULT_MQTT_STATUS_INTERVAL; cfg->mqtt_temp_interval = DEFAULT_MQTT_TEMP_INTERVAL; + cfg->mqtt_vsensor_interval = DEFAULT_MQTT_TEMP_INTERVAL; cfg->mqtt_rpm_interval = DEFAULT_MQTT_RPM_INTERVAL; cfg->mqtt_duty_interval = DEFAULT_MQTT_DUTY_INTERVAL; cfg->mqtt_ha_discovery_prefix[0] = 0; @@ -674,6 +681,9 @@ cJSON *config_to_json(const struct fanpico_config *cfg) if (cfg->mqtt_temp_interval != DEFAULT_MQTT_TEMP_INTERVAL) cJSON_AddItemToObject(config, "mqtt_temp_interval", cJSON_CreateNumber(cfg->mqtt_temp_interval)); + if (cfg->mqtt_vsensor_interval != DEFAULT_MQTT_TEMP_INTERVAL) + cJSON_AddItemToObject(config, "mqtt_vsensor_interval", + cJSON_CreateNumber(cfg->mqtt_vsensor_interval)); if (cfg->mqtt_rpm_interval != DEFAULT_MQTT_RPM_INTERVAL) cJSON_AddItemToObject(config, "mqtt_rpm_interval", cJSON_CreateNumber(cfg->mqtt_rpm_interval)); @@ -685,6 +695,21 @@ cJSON *config_to_json(const struct fanpico_config *cfg) cJSON_CreateString( bitmask_to_str(cfg->mqtt_temp_mask, SENSOR_MAX_COUNT, 1, true))); + if (cfg->mqtt_vtemp_mask) + cJSON_AddItemToObject(config, "mqtt_vtemp_mask", + cJSON_CreateString( + bitmask_to_str(cfg->mqtt_vtemp_mask, VSENSOR_MAX_COUNT, + 1, true))); + if (cfg->mqtt_vhumidity_mask) + cJSON_AddItemToObject(config, "mqtt_vhumidity_mask", + cJSON_CreateString( + bitmask_to_str(cfg->mqtt_vhumidity_mask, VSENSOR_MAX_COUNT, + 1, true))); + if (cfg->mqtt_vpressure_mask) + cJSON_AddItemToObject(config, "mqtt_vpressure_mask", + cJSON_CreateString( + bitmask_to_str(cfg->mqtt_vpressure_mask, VSENSOR_MAX_COUNT, + 1, true))); if (cfg->mqtt_fan_rpm_mask) cJSON_AddItemToObject(config, "mqtt_fan_rpm_mask", cJSON_CreateString( @@ -708,6 +733,15 @@ cJSON *config_to_json(const struct fanpico_config *cfg) if (strlen(cfg->mqtt_temp_topic) > 0) cJSON_AddItemToObject(config, "mqtt_temp_topic", cJSON_CreateString(cfg->mqtt_temp_topic)); + if (strlen(cfg->mqtt_vtemp_topic) > 0) + cJSON_AddItemToObject(config, "mqtt_vtemp_topic", + cJSON_CreateString(cfg->mqtt_vtemp_topic)); + if (strlen(cfg->mqtt_vhumidity_topic) > 0) + cJSON_AddItemToObject(config, "mqtt_vhumidity_topic", + cJSON_CreateString(cfg->mqtt_vhumidity_topic)); + if (strlen(cfg->mqtt_vpressure_topic) > 0) + cJSON_AddItemToObject(config, "mqtt_vpressure_topic", + cJSON_CreateString(cfg->mqtt_vpressure_topic)); if (strlen(cfg->mqtt_fan_rpm_topic) > 0) cJSON_AddItemToObject(config, "mqtt_fan_rpm_topic", cJSON_CreateString(cfg->mqtt_fan_rpm_topic)); @@ -1018,6 +1052,9 @@ int json_to_config(cJSON *config, struct fanpico_config *cfg) if ((ref = cJSON_GetObjectItem(config, "mqtt_temp_interval"))) { cfg->mqtt_temp_interval = cJSON_GetNumberValue(ref); } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vsensor_interval"))) { + cfg->mqtt_vsensor_interval = cJSON_GetNumberValue(ref); + } if ((ref = cJSON_GetObjectItem(config, "mqtt_rpm_interval"))) { cfg->mqtt_rpm_interval = cJSON_GetNumberValue(ref); } @@ -1028,6 +1065,18 @@ int json_to_config(cJSON *config, struct fanpico_config *cfg) if (!str_to_bitmask(cJSON_GetStringValue(ref), SENSOR_MAX_COUNT, &m, 1)) cfg->mqtt_temp_mask = m; } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vtemp_mask"))) { + if (!str_to_bitmask(cJSON_GetStringValue(ref), VSENSOR_MAX_COUNT, &m, 1)) + cfg->mqtt_vtemp_mask = m; + } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vhumidity_mask"))) { + if (!str_to_bitmask(cJSON_GetStringValue(ref), VSENSOR_MAX_COUNT, &m, 1)) + cfg->mqtt_vhumidity_mask = m; + } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vpressure_mask"))) { + if (!str_to_bitmask(cJSON_GetStringValue(ref), VSENSOR_MAX_COUNT, &m, 1)) + cfg->mqtt_vpressure_mask = m; + } if ((ref = cJSON_GetObjectItem(config, "mqtt_fan_rpm_mask"))) { if (!str_to_bitmask(cJSON_GetStringValue(ref), FAN_MAX_COUNT, &m, 1)) cfg->mqtt_fan_rpm_mask = m; @@ -1048,6 +1097,18 @@ int json_to_config(cJSON *config, struct fanpico_config *cfg) if ((val = cJSON_GetStringValue(ref))) strncopy(cfg->mqtt_temp_topic, val, sizeof(cfg->mqtt_temp_topic)); } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vtemp_topic"))) { + if ((val = cJSON_GetStringValue(ref))) + strncopy(cfg->mqtt_vtemp_topic, val, sizeof(cfg->mqtt_vtemp_topic)); + } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vhumidity_topic"))) { + if ((val = cJSON_GetStringValue(ref))) + strncopy(cfg->mqtt_vhumidity_topic, val, sizeof(cfg->mqtt_vhumidity_topic)); + } + if ((ref = cJSON_GetObjectItem(config, "mqtt_vpressure_topic"))) { + if ((val = cJSON_GetStringValue(ref))) + strncopy(cfg->mqtt_vpressure_topic, val, sizeof(cfg->mqtt_vpressure_topic)); + } if ((ref = cJSON_GetObjectItem(config, "mqtt_fan_rpm_topic"))) { if ((val = cJSON_GetStringValue(ref))) strncopy(cfg->mqtt_fan_rpm_topic, val, sizeof(cfg->mqtt_fan_rpm_topic)); diff --git a/src/fanpico.h b/src/fanpico.h index 393f21a..4846a8a 100644 --- a/src/fanpico.h +++ b/src/fanpico.h @@ -256,16 +256,23 @@ struct fanpico_config { char mqtt_cmd_topic[MQTT_MAX_TOPIC_LEN + 1]; char mqtt_resp_topic[MQTT_MAX_TOPIC_LEN + 1]; uint16_t mqtt_temp_mask; + uint16_t mqtt_vtemp_mask; + uint16_t mqtt_vhumidity_mask; + uint16_t mqtt_vpressure_mask; uint16_t mqtt_fan_rpm_mask; uint16_t mqtt_fan_duty_mask; uint16_t mqtt_mbfan_rpm_mask; uint16_t mqtt_mbfan_duty_mask; char mqtt_temp_topic[MQTT_MAX_TOPIC_LEN + 1]; + char mqtt_vtemp_topic[MQTT_MAX_TOPIC_LEN + 1]; + char mqtt_vhumidity_topic[MQTT_MAX_TOPIC_LEN + 1]; + char mqtt_vpressure_topic[MQTT_MAX_TOPIC_LEN + 1]; char mqtt_fan_rpm_topic[MQTT_MAX_TOPIC_LEN + 1]; char mqtt_fan_duty_topic[MQTT_MAX_TOPIC_LEN + 1]; char mqtt_mbfan_rpm_topic[MQTT_MAX_TOPIC_LEN + 1]; char mqtt_mbfan_duty_topic[MQTT_MAX_TOPIC_LEN + 1]; uint32_t mqtt_temp_interval; + uint32_t mqtt_vsensor_interval; uint32_t mqtt_rpm_interval; uint32_t mqtt_duty_interval; char mqtt_ha_discovery_prefix[32 + 1]; @@ -416,6 +423,7 @@ int fanpico_mqtt_client_active(); void fanpico_mqtt_reconnect(); void fanpico_mqtt_publish(); void fanpico_mqtt_publish_temp(); +void fanpico_mqtt_publish_vsensor(); void fanpico_mqtt_publish_rpm(); void fanpico_mqtt_publish_duty(); void fanpico_mqtt_scpi_command(); diff --git a/src/mqtt.c b/src/mqtt.c index bb298f6..8c8529a 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -460,6 +460,24 @@ static char* json_ha_discovery_message(const char *type, int idx, int count) cJSON_AddItemToObject(json, "device_class", cJSON_CreateString("temperature")); cJSON_AddItemToObject(json, "unit_of_measurement", cJSON_CreateString("°C")); } + else if (!strncmp(type, "vtemp", 5)) { + snprintf(tmp, sizeof(tmp), "Sensor: %s", cfg->vsensors[idx - 1].name); + cJSON_AddItemToObject(json, "name", cJSON_CreateString(tmp)); + cJSON_AddItemToObject(json, "device_class", cJSON_CreateString("temperature")); + cJSON_AddItemToObject(json, "unit_of_measurement", cJSON_CreateString("°C")); + } + else if (!strncmp(type, "vhumidity", 9)) { + snprintf(tmp, sizeof(tmp), "Sensor: %s", cfg->vsensors[idx - 1].name); + cJSON_AddItemToObject(json, "name", cJSON_CreateString(tmp)); + cJSON_AddItemToObject(json, "device_class", cJSON_CreateString("humidity")); + cJSON_AddItemToObject(json, "unit_of_measurement", cJSON_CreateString("%")); + } + else if (!strncmp(type, "vpressure", 9)) { + snprintf(tmp, sizeof(tmp), "Sensor: %s", cfg->vsensors[idx - 1].name); + cJSON_AddItemToObject(json, "name", cJSON_CreateString(tmp)); + cJSON_AddItemToObject(json, "device_class", cJSON_CreateString("pressure")); + cJSON_AddItemToObject(json, "unit_of_measurement", cJSON_CreateString("hPa")); + } else if (!strncmp(type, "fanrpm", 6)) { snprintf(tmp, sizeof(tmp), "Fan: %s", cfg->fans[idx - 1].name); cJSON_AddItemToObject(json, "name", cJSON_CreateString(tmp)); @@ -559,6 +577,24 @@ static void fanpico_mqtt_ha_discovery() } } + for (int i = 0; i < VSENSOR_COUNT; i++) { + if (cfg->mqtt_vtemp_mask & (1 << i)) { + snprintf(topic, sizeof(topic), "%s_vt%d/config", mqtt_ha_base_topic, i + 1); + if (send_ha_discovery_msg(topic, "vtemp", i + 1, count++)) + return; + } + if (cfg->mqtt_vhumidity_mask & (1 << i)) { + snprintf(topic, sizeof(topic), "%s_vh%d/config", mqtt_ha_base_topic, i + 1); + if (send_ha_discovery_msg(topic, "vhumidity", i + 1, count++)) + return; + } + if (cfg->mqtt_vpressure_mask & (1 << i)) { + snprintf(topic, sizeof(topic), "%s_vp%d/config", mqtt_ha_base_topic, i + 1); + if (send_ha_discovery_msg(topic, "vpressure", i + 1, count++)) + return; + } + } + for (int i = 0; i < FAN_COUNT; i++) { if (cfg->mqtt_fan_rpm_mask & (1 << i)) { snprintf(topic, sizeof(topic), "%s_fr%d/config", mqtt_ha_base_topic, i + 1); @@ -602,6 +638,21 @@ static char* json_ha_state_message() } } + for (int i = 0; i < VSENSOR_COUNT; i++) { + if (cfg->mqtt_vtemp_mask & (1 << i)) { + snprintf(name, sizeof(name), "vtemp%d", i + 1); + cJSON_AddItemToObject(json, name, cJSON_CreateNumber(round_decimal(st->vtemp[i], 1))); + } + if (cfg->mqtt_vhumidity_mask & (1 << i)) { + snprintf(name, sizeof(name), "vhumidity%d", i + 1); + cJSON_AddItemToObject(json, name, cJSON_CreateNumber(round_decimal(st->vhumidity[i], 0))); + } + if (cfg->mqtt_vpressure_mask & (1 << i)) { + snprintf(name, sizeof(name), "vpressure%d", i + 1); + cJSON_AddItemToObject(json, name, cJSON_CreateNumber(round_decimal(st->vpressure[i], 0))); + } + } + for (int i = 0; i < FAN_COUNT; i++) { if (cfg->mqtt_fan_rpm_mask & (1 << i)) { float rpm = st->fan_freq[i] * 60 / cfg->fans[i].rpm_factor; @@ -770,6 +821,39 @@ void fanpico_mqtt_publish_temp() log_msg(LOG_DEBUG, "fanpico_mqtt_publish_temp(): end"); } +void fanpico_mqtt_publish_vsensor() +{ + const struct fanpico_state *st = fanpico_state; + char topic[MQTT_MAX_TOPIC_LEN + 8]; + char buf[64]; + + if (!mqtt_client) + return; + + log_msg(LOG_DEBUG, "fanpico_mqtt_publish_vsensor(): start"); + for (int i = 0; i < VSENSOR_COUNT; i++) { + if (strlen(cfg->mqtt_vtemp_topic) > 0 && cfg->mqtt_vtemp_mask & (1 << i)) { + snprintf(topic, sizeof(topic), cfg->mqtt_vtemp_topic, i + 1); + snprintf(buf, sizeof(buf), "%.1f", st->vtemp[i]); + mqtt_publish_message(topic, buf, strlen(buf), mqtt_qos, 0, + cfg->mqtt_vtemp_topic); + } + if (strlen(cfg->mqtt_vhumidity_topic) > 0 && cfg->mqtt_vhumidity_mask & (1 << i)) { + snprintf(topic, sizeof(topic), cfg->mqtt_vhumidity_topic, i + 1); + snprintf(buf, sizeof(buf), "%.0f", st->vhumidity[i]); + mqtt_publish_message(topic, buf, strlen(buf), mqtt_qos, 0, + cfg->mqtt_vhumidity_topic); + } + if (strlen(cfg->mqtt_vpressure_topic) > 0 && cfg->mqtt_vpressure_mask & (1 << i)) { + snprintf(topic, sizeof(topic), cfg->mqtt_vpressure_topic, i + 1); + snprintf(buf, sizeof(buf), "%.0f", st->vpressure[i]); + mqtt_publish_message(topic, buf, strlen(buf), mqtt_qos, 0, + cfg->mqtt_vpressure_topic); + } + } + log_msg(LOG_DEBUG, "fanpico_mqtt_publish_vsensor(): end"); +} + void fanpico_mqtt_publish_rpm() { const struct fanpico_state *st = fanpico_state; diff --git a/src/network.c b/src/network.c index 426d93d..134e611 100644 --- a/src/network.c +++ b/src/network.c @@ -242,6 +242,7 @@ void wifi_poll() static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(test_t, 0); static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(publish_status_t, 0); static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(publish_temp_t, 0); + static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(publish_vsensor_t, 0); static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(publish_rpm_t, 0); static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(publish_duty_t, 0); static absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(command_t, 0); @@ -295,6 +296,11 @@ void wifi_poll() fanpico_mqtt_publish_temp(); } } + if (cfg->mqtt_vsensor_interval > 0) { + if (time_passed(&publish_vsensor_t, cfg->mqtt_vsensor_interval * 1000)) { + fanpico_mqtt_publish_vsensor(); + } + } if (cfg->mqtt_rpm_interval > 0) { if (time_passed(&publish_rpm_t, cfg->mqtt_rpm_interval * 1000)) { fanpico_mqtt_publish_rpm();