Adding SGP Air Sensor I2C Driver (#769)

* Adding new driver for SGP30

* correct tasmota detection for SGP

* Correct mqtt publish

* Adding dependency in drv_tuyaMCU for bl0602
This commit is contained in:
Dheenhasty
2023-04-14 08:37:12 +02:00
committed by GitHub
parent 330fbd472e
commit 28556c06c7
13 changed files with 1302 additions and 867 deletions

View File

@ -58,6 +58,12 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) {
case HUMIDITY_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "humidity", index);
break;
case CO2_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "co2", index);
break;
case TVOC_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "tvoc", index);
break;
case BATTERY_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "battery", index);
break;
@ -96,6 +102,8 @@ void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDe
sprintf(info->channel, "switch/%s/config", uniq_id);
break;
case CO2_SENSOR:
case TVOC_SENSOR:
case POWER_SENSOR:
case BATTERY_SENSOR:
case BATTERY_VOLTAGE_SENSOR:
@ -186,6 +194,14 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload
isSensor = true;
sprintf(g_hassBuffer, "%s Humidity", CFG_GetShortDeviceName());
break;
case CO2_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "%s CO2", CFG_GetShortDeviceName());
break;
case TVOC_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "%s Tvoc", CFG_GetShortDeviceName());
break;
case BATTERY_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "%s Battery", CFG_GetShortDeviceName());
@ -282,10 +298,10 @@ HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type) {
cJSON_AddStringToObject(info->root, "clr_temp_cmd_t", g_hassBuffer); //color_temp_command_topic
cJSON_AddStringToObject(info->root, "clr_temp_stat_t", "~/led_temperature/get"); //color_temp_state_topic
sprintf(g_hassBuffer, "%.0f", led_temperature_min);
cJSON_AddStringToObject(info->root, "min_mirs", g_hassBuffer); //min_mireds
sprintf(g_hassBuffer, "%.0f", led_temperature_max);
cJSON_AddStringToObject(info->root, "max_mirs", g_hassBuffer); //max_mireds
}
@ -381,6 +397,18 @@ HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel) {
sprintf(g_hassBuffer, "~/%d/get", channel);
cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer);
break;
case CO2_SENSOR:
cJSON_AddStringToObject(info->root, "dev_cla", "carbon_dioxide");
cJSON_AddStringToObject(info->root, "unit_of_meas", "ppm");
sprintf(g_hassBuffer, "~/%d/get", channel);
cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer);
break;
case TVOC_SENSOR:
cJSON_AddStringToObject(info->root, "dev_cla", "volatile_organic_compounds");
cJSON_AddStringToObject(info->root, "unit_of_meas", "ppb");
sprintf(g_hassBuffer, "~/%d/get", channel);
cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer);
break;
case BATTERY_SENSOR:
cJSON_AddStringToObject(info->root, "dev_cla", "battery");
cJSON_AddStringToObject(info->root, "unit_of_meas", "%");

View File

@ -38,7 +38,12 @@ typedef enum {
/// @brief Battery level sensor in perc
BATTERY_SENSOR,
/// @brief Battery votage sensor in mV
BATTERY_VOLTAGE_SENSOR
BATTERY_VOLTAGE_SENSOR,
/// @brief CO2 sensor in ppm
CO2_SENSOR,
/// @brief TVOC sensor in ppb
TVOC_SENSOR
} ENTITY_TYPE;

View File

@ -1665,6 +1665,17 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
discoveryQueued = true;
}
else if (IS_PIN_AIR_SENSOR_ROLE(g_cfg.pins.roles[i])) {
dev_info = hass_init_sensor_device_info(CO2_SENSOR, PIN_GetPinChannelForPinIndex(i));
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
dev_info = hass_init_sensor_device_info(TVOC_SENSOR, PIN_GetPinChannel2ForPinIndex(i));
MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
hass_free_device_info(dev_info);
discoveryQueued = true;
}
}
@ -2109,7 +2120,7 @@ int http_fn_cfg_pins(http_request_t* request) {
poststr(request, "</select>");
// Primary linked channel
// Some roles do not need any channels
if ((si != IOR_SHT3X_CLK && si != IOR_CHT8305_CLK && si != IOR_Button_ToggleAll && si != IOR_Button_ToggleAll_n
if ((si != IOR_SGP_CLK && si != IOR_SHT3X_CLK && si != IOR_CHT8305_CLK && si != IOR_Button_ToggleAll && si != IOR_Button_ToggleAll_n
&& si != IOR_BL0937_CF && si != IOR_BL0937_CF1 && si != IOR_BL0937_SEL
&& si != IOR_LED_WIFI && si != IOR_LED_WIFI_n && si != IOR_LED_WIFI_n
&& !(si >= IOR_IRRecv && si <= IOR_DHT11)
@ -2120,7 +2131,7 @@ int http_fn_cfg_pins(http_request_t* request) {
}
// Secondary linked channel
// For button, is relay index to toggle on double click
if (si == IOR_Button || si == IOR_Button_n || IS_PIN_DHT_ROLE(si) || IS_PIN_TEMP_HUM_SENSOR_ROLE(si))
if (si == IOR_Button || si == IOR_Button_n || IS_PIN_DHT_ROLE(si) || IS_PIN_TEMP_HUM_SENSOR_ROLE(si) || IS_PIN_AIR_SENSOR_ROLE(si))
{
hprintf255(request, "<input class=\"hele\" name=\"e%i\" type=\"text\" value=\"%i\"/>", i, ch2);
}

View File

@ -21,19 +21,19 @@
#include "../driver/drv_local.h"
#include "../driver/drv_bl_shared.h"
void JSON_PrintKeyValue_String(void* request, jsonCb_t printer, const char *key, const char *value, bool bComma) {
void JSON_PrintKeyValue_String(void* request, jsonCb_t printer, const char* key, const char* value, bool bComma) {
printer(request, "\"%s\":\"%s\"", key, value);
if (bComma) {
printer(request, ",");
}
}
void JSON_PrintKeyValue_Int(void* request, jsonCb_t printer, const char *key, int value, bool bComma) {
void JSON_PrintKeyValue_Int(void* request, jsonCb_t printer, const char* key, int value, bool bComma) {
printer(request, "\"%s\":%i", key, value);
if (bComma) {
printer(request, ",");
}
}
void JSON_PrintKeyValue_Float(void* request, jsonCb_t printer, const char *key, float value, bool bComma) {
void JSON_PrintKeyValue_Float(void* request, jsonCb_t printer, const char* key, float value, bool bComma) {
printer(request, "\"%s\":%f", key, value);
if (bComma) {
printer(request, ",");
@ -117,10 +117,10 @@ static int http_tasmota_json_power(void* request, jsonCb_t printer) {
// it looks like they include C and W in color
if (LED_IsLedDriverChipRunning() || numPWMs == 5) {
sprintf(buff32, "%i,%i,%i,%i,%i",(int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2], (int)rgbcw[3], (int)rgbcw[4]);
sprintf(buff32, "%i,%i,%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2], (int)rgbcw[3], (int)rgbcw[4]);
}
else {
sprintf(buff32,"%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2]);
sprintf(buff32, "%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2]);
}
JSON_PrintKeyValue_String(request, printer, "Color", buff32, true);
sprintf(buff32, "%i,%i,%i", (int)hsv[0], (int)hsv[1], (int)hsv[2]);
@ -260,7 +260,7 @@ static int http_tasmota_json_ENERGY(void* request, jsonCb_t printer) {
}
*/
static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) {
float temperature, humidity;
float chan_val1, chan_val2;
int channel_1, channel_2, g_pin_1 = 0;
printer(request, ",");
if (DRV_IsRunning("SHT3X")) {
@ -268,15 +268,15 @@ static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) {
channel_1 = g_cfg.pins.channels[g_pin_1];
channel_2 = g_cfg.pins.channels2[g_pin_1];
temperature = CHANNEL_GetFloat(channel_1) / 10.0f;
humidity = CHANNEL_GetFloat(channel_2);
chan_val1 = CHANNEL_GetFloat(channel_1) / 10.0f;
chan_val2 = CHANNEL_GetFloat(channel_2);
// writer header
printer(request, "\"SHT3X\":");
// following check will clear NaN values
printer(request, "{");
printer(request, "\"Temperature\": %.1f,", temperature);
printer(request, "\"Humidity\": %.0f", humidity);
printer(request, "\"Temperature\": %.1f,", chan_val1);
printer(request, "\"Humidity\": %.0f", chan_val2);
// close ENERGY block
printer(request, "},");
}
@ -285,15 +285,32 @@ static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) {
channel_1 = g_cfg.pins.channels[g_pin_1];
channel_2 = g_cfg.pins.channels2[g_pin_1];
temperature = CHANNEL_GetFloat(channel_1) / 10.0f;
humidity = CHANNEL_GetFloat(channel_2);
chan_val1 = CHANNEL_GetFloat(channel_1) / 10.0f;
chan_val2 = CHANNEL_GetFloat(channel_2);
// writer header
printer(request, "\"CHT8305\":");
// following check will clear NaN values
printer(request, "{");
printer(request, "\"Temperature\": %.1f,", temperature);
printer(request, "\"Humidity\": %.0f", humidity);
printer(request, "\"Temperature\": %.1f,", chan_val1);
printer(request, "\"Humidity\": %.0f", chan_val2);
// close ENERGY block
printer(request, "},");
}
if (DRV_IsRunning("SGP")) {
g_pin_1 = PIN_FindPinIndexForRole(IOR_SGP_DAT, g_pin_1);
channel_1 = g_cfg.pins.channels[g_pin_1];
channel_2 = g_cfg.pins.channels2[g_pin_1];
chan_val1 = CHANNEL_GetFloat(channel_1);
chan_val2 = CHANNEL_GetFloat(channel_2);
// writer header
printer(request, "\"SGP\":");
// following check will clear NaN values
printer(request, "{");
printer(request, "\"CO2\": %.0f,", chan_val1);
printer(request, "\"Tvoc\": %.0f", chan_val2);
// close ENERGY block
printer(request, "},");
}
@ -978,7 +995,7 @@ int JSON_ProcessCommandReply(const char* cmd, const char* arg, void* request, js
}
else if (!wal_strnicmp(cmd, "SSID1", 5)) {
printer(request, "{");
JSON_PrintKeyValue_String(request,printer,"SSID1", CFG_GetWiFiSSID(),false);
JSON_PrintKeyValue_String(request, printer, "SSID1", CFG_GetWiFiSSID(), false);
printer(request, "}");
}
else if (!wal_strnicmp(cmd, "LED_Map", 7)) {

View File

@ -448,8 +448,9 @@ const char* htmlPinRoleNames[] = {
"TM1637_DIO",
"TM1637_CLK",
"BL0937SEL_n",
"DoorSnsrWSleep_pd",
"error",
"DoorSnsrWSleep_pd",
"SGP_CLK",
"SGP_DAT",
"error",
"error",
"error",