From 7e0ae16c4fefab914884d22a9ded025c26cc100f Mon Sep 17 00:00:00 2001 From: caphm Date: Thu, 15 Aug 2019 11:55:59 +0200 Subject: [PATCH 1/8] Add MAC address to Home Assistant Discovery Message, fixes #6226 --- sonoff/xdrv_12_home_assistant.ino | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sonoff/xdrv_12_home_assistant.ino b/sonoff/xdrv_12_home_assistant.ino index afdfd047f..dcd0a1e04 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -129,6 +129,7 @@ const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = ",\"uniq_id\":\"%s\"," "\"device\":{\"identifiers\":[\"%06X\"]," + "\"connections\":[[\"mac\",\"%s\"]]," "\"name\":\"%s\"," "\"model\":\"%s\"," "\"sw_version\":\"%s%s\"," @@ -136,7 +137,8 @@ const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = ",\"uniq_id\":\"%s\"," - "\"device\":{\"identifiers\":[\"%06X\"]}"; + "\"device\":{\"identifiers\":[\"%06X\"]," + "\"connections\":[[\"mac\",\"%s\"]]}"; const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM = ",\"~\":\"%s\""; @@ -237,7 +239,7 @@ void HAssAnnounceRelayLight(void) Shorten(&availability_topic, prefix); Response_P(HASS_DISCOVER_RELAY, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix); if (is_light) { @@ -317,7 +319,7 @@ void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint Shorten(&state_topic, prefix); Shorten(&availability_topic, prefix); Response_P(HASS_DISCOVER_BUTTON_SWITCH, name, state_topic, Settings.state_text[toggle?2:1], availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); if (strlen(prefix) > 0 ) TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix); if (toggle) TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_TOGGLE); else TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_ONOFF, Settings.state_text[0]); @@ -416,7 +418,7 @@ void HAssAnnounceSensor(const char* sensorname, const char* subsensortype) Shorten(&availability_topic, prefix); Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId()); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP.getChipId(), WiFi.macAddress().c_str()); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix); if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) { TryResponseAppend_P(HASS_DISCOVER_SENSOR_TEMP, TempUnit(), sensorname); @@ -516,7 +518,7 @@ void HAssAnnounceStatusSensor(void) Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic); TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP.getChipId(), + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP.getChipId(), WiFi.macAddress().c_str(), Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix); TryResponseAppend_P(PSTR("}")); From 807aff4675c5addd0c3d6488b714cab175d7b184 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 16 Aug 2019 07:37:16 +0200 Subject: [PATCH 2/8] subscribe with strings, smal bug fixes --- scripter.md | 3 +- sonoff/xdrv_10_scripter.ino | 121 +++++++++++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/scripter.md b/scripter.md index 2820b0f84..e82a8c1bc 100644 --- a/scripter.md +++ b/scripter.md @@ -49,7 +49,7 @@ memory is dynamically allocated as a result of the D section. copying a string to a number or reverse is supported >**\>B** -executed on BOOT time +executed on BOOT time and script save >**\>T** executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section @@ -183,6 +183,7 @@ and on the same line conditions may be bracketed e.g. if ((a==b) and ((c==d) or **spin(x m)** set gpio pin x (0-16) to value m (0,1) only the last bit is used, so even values set the pin to zero and uneven values set the pin to 1 **spinm(x m)** set pin mode gpio pin x (0-16) to mode m (input=0,output=1,input with pullup=2) **ws2812(array)** copies an array (defined with m:name) to the WS2812 LED chain the array should be defined as long as the number of pixels. the color is coded as 24 bit RGB +**hsvrgb(h s v)** converts hue (0-360), saturation (0-100) and value (0-100) to RGB color >**#name** names a subroutine, subroutines are called with **=#name** **#name(param)** names a subroutines with a parameter is called with **=#name(param)** diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index 02d8513dd..c4ff1dc54 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -109,7 +109,6 @@ struct M_FILT { float rbuff[1]; }; - typedef union { uint8_t data; struct { @@ -200,8 +199,6 @@ void RulesTeleperiod(void) { if (bitRead(Settings.rule_enabled, 0) && mqtt_data[0]) Run_Scripter(">T",2, mqtt_data); } -//#define USE_24C256 - // EEPROM MACROS #ifdef USE_24C256 #ifndef USE_SCRIPT_FATFS @@ -710,6 +707,91 @@ float DoMedian5(uint8_t index, float in) { return median_array(mf->buffer,MEDIAN_SIZE); } +#ifdef USE_LIGHT +#ifdef USE_WS2812 +uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) { +float r = 0, g = 0, b = 0; +struct HSV { + float H; + float S; + float V; +} hsv; + +hsv.H=hue; +hsv.S=(float)saturation/100.0; +hsv.V=(float)value/100.0; + +if (hsv.S == 0) { + r = hsv.V; + g = hsv.V; + b = hsv.V; + } else { + int i; + float f, p, q, t; + + if (hsv.H == 360) + hsv.H = 0; + else + hsv.H = hsv.H / 60; + + i = (int)trunc(hsv.H); + f = hsv.H - i; + + p = hsv.V * (1.0 - hsv.S); + q = hsv.V * (1.0 - (hsv.S * f)); + t = hsv.V * (1.0 - (hsv.S * (1.0 - f))); + + switch (i) + { + case 0: + r = hsv.V; + g = t; + b = p; + break; + + case 1: + r = q; + g = hsv.V; + b = p; + break; + + case 2: + r = p; + g = hsv.V; + b = t; + break; + + case 3: + r = p; + g = q; + b = hsv.V; + break; + + case 4: + r = t; + g = p; + b = hsv.V; + break; + + default: + r = hsv.V; + g = p; + b = q; + break; + } + + } + + uint8_t ir,ig,ib; + ir=r*255; + ig=g*255; + ib=b*255; + + uint32_t rgb=(ir<<16)|(ig<<8)|ib; + return rgb; +} +#endif +#endif // vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number // no flash strings here for performance reasons!!! @@ -1212,6 +1294,30 @@ chknext: } goto strexit; } +#ifdef USE_LIGHT +#ifdef USE_WS2812 + if (!strncmp(vname,"hsvrgb(",7)) { + lp=GetNumericResult(lp+7,OPER_EQU,&fvar,0); + if (fvar<0 || fvar>360) fvar=0; + SCRIPT_SKIP_SPACES + // arg2 + float fvar2; + lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); + if (fvar2<0 || fvar2>100) fvar2=0; + SCRIPT_SKIP_SPACES + // arg3 + float fvar3; + lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); + if (fvar3<0 || fvar3>100) fvar3=0; + + fvar=HSVToRGB(fvar,fvar2,fvar3); + + lp++; + len=0; + goto exit; + } +#endif +#endif break; case 'i': if (!strncmp(vname,"int(",4)) { @@ -2046,6 +2152,9 @@ exit: #define IF_NEST 8 // execute section of scripter int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { + + if (tasm_cmd_activ && tlen>0) return 0; + uint8_t vtype=0,sindex,xflg,floop=0,globvindex; int8_t globaindex; struct T_INDEX ind; @@ -2060,9 +2169,6 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { check=1; } - if (tasm_cmd_activ) return 0; - - float *dfvar,*cv_count,cv_max,cv_inc; char *cv_ptr; float fvar=0,fvar1,sysvar,swvar; @@ -3224,10 +3330,11 @@ bool ScriptMqttData(void) } } value.trim(); + //Create an new event. Cannot directly call RulesProcessEvent(). //snprintf_P(event_data, sizeof(event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str()); char sbuffer[128]; - snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=%s\n"), event_item.Event.c_str(), value.c_str()); + snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=\"%s\"\n"), event_item.Event.c_str(), value.c_str()); //toLog(sbuffer); execute_script(sbuffer); } From 0e4d4a889acb143841d2f7f9df37b2da9a1e1da4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 14:41:02 +0200 Subject: [PATCH 3/8] Refactor Energy code saving space Refactor Energy code saving space --- sonoff/xdrv_01_webserver.ino | 1 - sonoff/xdrv_03_energy.ino | 354 ++++++++++++++++++----------------- sonoff/xnrg_01_hlw8012.ino | 220 +++++++++++----------- sonoff/xnrg_02_cse7766.ino | 122 ++++++------ sonoff/xnrg_03_pzem004t.ino | 16 +- sonoff/xnrg_04_mcp39f501.ino | 36 ++-- sonoff/xnrg_05_pzem_ac.ino | 20 +- sonoff/xnrg_06_pzem_dc.ino | 18 +- sonoff/xnrg_07_ade7953.ino | 100 +++++----- 9 files changed, 448 insertions(+), 439 deletions(-) diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 6ccc3ed10..f11480c58 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -488,7 +488,6 @@ struct WEB { uint8_t config_xor_on_set = CONFIG_FILE_XOR; } Web; - // Helper function to avoid code duplication (saves 4k Flash) static void WebGetArg(const char* arg, char* out, size_t max) { diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index b331c98cd..37fc8f6d5 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -67,94 +67,98 @@ void (* const EnergyCommand[])(void) PROGMEM = { #endif // USE_ENERGY_MARGIN_DETECTION &CmndEnergyReset }; -float energy_voltage = 0; // 123.1 V -float energy_current = 0; // 123.123 A -float energy_active_power = 0; // 123.1 W -float energy_apparent_power = NAN; // 123.1 VA -float energy_reactive_power = NAN; // 123.1 VAr -float energy_power_factor = NAN; // 0.12 -float energy_frequency = NAN; // 123.1 Hz -float energy_start = 0; // 12345.12345 kWh total previous +struct ENERGY { + float voltage = 0; // 123.1 V + float current = 0; // 123.123 A + float active_power = 0; // 123.1 W + float apparent_power = NAN; // 123.1 VA + float reactive_power = NAN; // 123.1 VAr + float power_factor = NAN; // 0.12 + float frequency = NAN; // 123.1 Hz + float start_energy = 0; // 12345.12345 kWh total previous -float energy_daily = 0; // 123.123 kWh -float energy_total = 0; // 12345.12345 kWh -unsigned long energy_kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to energy_kWhtoday (HLW and CSE only) -unsigned long energy_kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily -unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily + float daily = 0; // 123.123 kWh + float total = 0; // 12345.12345 kWh -uint8_t energy_command_code = 0; -uint8_t energy_data_valid = 0; + unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only) + unsigned long kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily + unsigned long period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily -bool energy_voltage_available = true; // Enable if voltage is measured -bool energy_current_available = true; // Enable if current is measured + uint8_t fifth_second = 0; + uint8_t command_code = 0; + uint8_t data_valid = 0; -bool energy_type_dc = false; -bool energy_power_on = true; + bool voltage_available = true; // Enable if voltage is measured + bool current_available = true; // Enable if current is measured + + bool type_dc = false; + bool power_on = true; #ifdef USE_ENERGY_MARGIN_DETECTION -float energy_power_last[3] = { 0 }; -uint8_t energy_power_delta = 0; -bool energy_min_power_flag = false; -bool energy_max_power_flag = false; -bool energy_min_voltage_flag = false; -bool energy_max_voltage_flag = false; -bool energy_min_current_flag = false; -bool energy_max_current_flag = false; -uint8_t energy_power_steady_cntr = 8; // Allow for power on stabilization + float power_history[3] = { 0 }; + uint8_t power_steady_counter = 8; // Allow for power on stabilization + uint8_t power_delta = 0; + bool min_power_flag = false; + bool max_power_flag = false; + bool min_voltage_flag = false; + bool max_voltage_flag = false; + bool min_current_flag = false; + bool max_current_flag = false; #ifdef USE_ENERGY_POWER_LIMIT -uint16_t energy_mplh_counter = 0; -uint16_t energy_mplw_counter = 0; -uint8_t energy_mplr_counter = 0; -uint8_t energy_max_energy_state = 0; + uint16_t mplh_counter = 0; + uint16_t mplw_counter = 0; + uint8_t mplr_counter = 0; + uint8_t max_energy_state = 0; #endif // USE_ENERGY_POWER_LIMIT -#endif // USE_ENERGY_MARGIN_DETECTION -uint8_t energy_fifth_second = 0; +#endif // USE_ENERGY_MARGIN_DETECTION +} Energy; + Ticker ticker_energy; /********************************************************************************************/ void EnergyUpdateToday(void) { - if (energy_kWhtoday_delta > 1000) { - unsigned long delta = energy_kWhtoday_delta / 1000; - energy_kWhtoday_delta -= (delta * 1000); - energy_kWhtoday += delta; + if (Energy.kWhtoday_delta > 1000) { + unsigned long delta = Energy.kWhtoday_delta / 1000; + Energy.kWhtoday_delta -= (delta * 1000); + Energy.kWhtoday += delta; } - RtcSettings.energy_kWhtoday = energy_kWhtoday; - energy_daily = (float)energy_kWhtoday / 100000; - energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; + RtcSettings.energy_kWhtoday = Energy.kWhtoday; + Energy.daily = (float)Energy.kWhtoday / 100000; + Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000; } /*********************************************************************************************/ void Energy200ms(void) { - energy_power_on = (power != 0) | Settings.flag.no_power_on_check; + Energy.power_on = (power != 0) | Settings.flag.no_power_on_check; - energy_fifth_second++; - if (5 == energy_fifth_second) { - energy_fifth_second = 0; + Energy.fifth_second++; + if (5 == Energy.fifth_second) { + Energy.fifth_second = 0; XnrgCall(FUNC_ENERGY_EVERY_SECOND); if (RtcTime.valid) { if (LocalTime() == Midnight()) { - Settings.energy_kWhyesterday = energy_kWhtoday; - Settings.energy_kWhtotal += energy_kWhtoday; + Settings.energy_kWhyesterday = Energy.kWhtoday; + Settings.energy_kWhtotal += Energy.kWhtoday; RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal; - energy_kWhtoday = 0; - energy_kWhtoday_delta = 0; - energy_period = energy_kWhtoday; + Energy.kWhtoday = 0; + Energy.kWhtoday_delta = 0; + Energy.period = Energy.kWhtoday; EnergyUpdateToday(); #if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - energy_max_energy_state = 3; + Energy.max_energy_state = 3; #endif // USE_ENERGY_POWER_LIMIT } #if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - if ((RtcTime.hour == Settings.energy_max_energy_start) && (3 == energy_max_energy_state)) { - energy_max_energy_state = 0; + if ((RtcTime.hour == Settings.energy_max_energy_start) && (3 == Energy.max_energy_state )) { + Energy.max_energy_state = 0; } #endif // USE_ENERGY_POWER_LIMIT @@ -167,8 +171,8 @@ void Energy200ms(void) void EnergySaveState(void) { Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; - Settings.energy_kWhtoday = energy_kWhtoday; - RtcSettings.energy_kWhtoday = energy_kWhtoday; + Settings.energy_kWhtoday = Energy.kWhtoday; + RtcSettings.energy_kWhtoday = Energy.kWhtoday; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; } @@ -197,55 +201,55 @@ void EnergyMarginCheck(void) bool flag; bool jsonflg; - if (energy_power_steady_cntr) { - energy_power_steady_cntr--; + if (Energy.power_steady_counter) { + Energy.power_steady_counter--; return; } if (Settings.energy_power_delta) { - float delta = abs(energy_power_last[0] - energy_active_power); + float delta = abs(Energy.power_history[0] - Energy.active_power); // Any delta compared to minimal delta - float min_power = (energy_power_last[0] > energy_active_power) ? energy_active_power : energy_power_last[0]; + float min_power = (Energy.power_history[0] > Energy.active_power) ? Energy.active_power : Energy.power_history[0]; if (((delta / min_power) * 100) > Settings.energy_power_delta) { - energy_power_delta = 1; - energy_power_last[1] = energy_active_power; // We only want one report so reset history - energy_power_last[2] = energy_active_power; + Energy.power_delta = 1; + Energy.power_history[1] = Energy.active_power; // We only want one report so reset history + Energy.power_history[2] = Energy.active_power; } } - energy_power_last[0] = energy_power_last[1]; // Shift in history every second allowing power changes to settle for up to three seconds - energy_power_last[1] = energy_power_last[2]; - energy_power_last[2] = energy_active_power; + Energy.power_history[0] = Energy.power_history[1]; // Shift in history every second allowing power changes to settle for up to three seconds + Energy.power_history[1] = Energy.power_history[2]; + Energy.power_history[2] = Energy.active_power; - if (energy_power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) { - energy_power_u = (uint16_t)(energy_active_power); - energy_voltage_u = (uint16_t)(energy_voltage); - energy_current_u = (uint16_t)(energy_current * 1000); + if (Energy.power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) { + energy_power_u = (uint16_t)(Energy.active_power); + energy_voltage_u = (uint16_t)(Energy.voltage); + energy_current_u = (uint16_t)(Energy.current * 1000); DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); Response_P(PSTR("{")); jsonflg = false; - if (EnergyMargin(false, Settings.energy_min_power, energy_power_u, flag, energy_min_power_flag)) { + if (EnergyMargin(false, Settings.energy_min_power, energy_power_u, flag, Energy.min_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings.energy_max_power, energy_power_u, flag, energy_max_power_flag)) { + if (EnergyMargin(true, Settings.energy_max_power, energy_power_u, flag, Energy.max_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Settings.energy_min_voltage, energy_voltage_u, flag, energy_min_voltage_flag)) { + if (EnergyMargin(false, Settings.energy_min_voltage, energy_voltage_u, flag, Energy.min_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings.energy_max_voltage, energy_voltage_u, flag, energy_max_voltage_flag)) { + if (EnergyMargin(true, Settings.energy_max_voltage, energy_voltage_u, flag, Energy.max_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Settings.energy_min_current, energy_current_u, flag, energy_min_current_flag)) { + if (EnergyMargin(false, Settings.energy_min_current, energy_current_u, flag, Energy.min_current_flag)) { ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings.energy_max_current, energy_current_u, flag, energy_max_current_flag)) { + if (EnergyMargin(true, Settings.energy_max_current, energy_current_u, flag, Energy.max_current_flag)) { ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } @@ -259,35 +263,35 @@ void EnergyMarginCheck(void) #ifdef USE_ENERGY_POWER_LIMIT // Max Power if (Settings.energy_max_power_limit) { - if (energy_active_power > Settings.energy_max_power_limit) { - if (!energy_mplh_counter) { - energy_mplh_counter = Settings.energy_max_power_limit_hold; + if (Energy.active_power > Settings.energy_max_power_limit) { + if (!Energy.mplh_counter) { + Energy.mplh_counter = Settings.energy_max_power_limit_hold; } else { - energy_mplh_counter--; - if (!energy_mplh_counter) { + Energy.mplh_counter--; + if (!Energy.mplh_counter) { Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : ""); MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); EnergyMqttShow(); ExecuteCommandPower(1, POWER_OFF, SRC_MAXPOWER); - if (!energy_mplr_counter) { - energy_mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1; + if (!Energy.mplr_counter) { + Energy.mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1; } - energy_mplw_counter = Settings.energy_max_power_limit_window; + Energy.mplw_counter = Settings.energy_max_power_limit_window; } } } else if (power && (energy_power_u <= Settings.energy_max_power_limit)) { - energy_mplh_counter = 0; - energy_mplr_counter = 0; - energy_mplw_counter = 0; + Energy.mplh_counter = 0; + Energy.mplr_counter = 0; + Energy.mplw_counter = 0; } if (!power) { - if (energy_mplw_counter) { - energy_mplw_counter--; + if (Energy.mplw_counter) { + Energy.mplw_counter--; } else { - if (energy_mplr_counter) { - energy_mplr_counter--; - if (energy_mplr_counter) { + if (Energy.mplr_counter) { + Energy.mplr_counter--; + if (Energy.mplr_counter) { Response_P(PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1)); MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR)); ExecuteCommandPower(1, POWER_ON, SRC_MAXPOWER); @@ -303,16 +307,16 @@ void EnergyMarginCheck(void) // Max Energy if (Settings.energy_max_energy) { - energy_daily_u = (uint16_t)(energy_daily * 1000); - if (!energy_max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) { - energy_max_energy_state = 1; + energy_daily_u = (uint16_t)(Energy.daily * 1000); + if (!Energy.max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) { + Energy.max_energy_state = 1; Response_P(PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); ExecuteCommandPower(1, POWER_ON, SRC_MAXENERGY); } - else if ((1 == energy_max_energy_state) && (energy_daily_u >= Settings.energy_max_energy)) { - energy_max_energy_state = 2; - dtostrfd(energy_daily, 3, mqtt_data); + else if ((1 == Energy.max_energy_state ) && (energy_daily_u >= Settings.energy_max_energy)) { + Energy.max_energy_state = 2; + dtostrfd(Energy.daily, 3, mqtt_data); Response_P(PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : ""); MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); EnergyMqttShow(); @@ -321,7 +325,7 @@ void EnergyMarginCheck(void) } #endif // USE_ENERGY_POWER_LIMIT - if (energy_power_delta) { EnergyMqttShow(); } + if (Energy.power_delta) { EnergyMqttShow(); } } void EnergyMqttShow(void) @@ -334,7 +338,7 @@ void EnergyMqttShow(void) tele_period = tele_period_save; ResponseJsonEnd(); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - energy_power_delta = 0; + Energy.power_delta = 0; } #endif // USE_ENERGY_MARGIN_DETECTION @@ -345,16 +349,16 @@ void EnergyOverTempCheck() SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP); } } - if (energy_data_valid <= ENERGY_WATCHDOG) { - energy_data_valid++; - if (energy_data_valid > ENERGY_WATCHDOG) { + if (Energy.data_valid <= ENERGY_WATCHDOG) { + Energy.data_valid++; + if (Energy.data_valid > ENERGY_WATCHDOG) { // Reset energy registers - energy_voltage = 0; - energy_current = 0; - energy_active_power = 0; - if (!isnan(energy_frequency)) { energy_frequency = 0; } - if (!isnan(energy_power_factor)) { energy_power_factor = 0; } - energy_start = 0; + Energy.voltage = 0; + Energy.current = 0; + Energy.active_power = 0; + if (!isnan(Energy.frequency)) { Energy.frequency = 0; } + if (!isnan(Energy.power_factor)) { Energy.power_factor = 0; } + Energy.start_energy = 0; } } } @@ -386,13 +390,13 @@ void CmndEnergyReset(void) if (p != XdrvMailbox.data) { switch (XdrvMailbox.index) { case 1: - energy_kWhtoday = lnum *100; - energy_kWhtoday_delta = 0; - energy_period = energy_kWhtoday; - Settings.energy_kWhtoday = energy_kWhtoday; - RtcSettings.energy_kWhtoday = energy_kWhtoday; - energy_daily = (float)energy_kWhtoday / 100000; - if (!RtcSettings.energy_kWhtotal && !energy_kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); } + Energy.kWhtoday = lnum *100; + Energy.kWhtoday_delta = 0; + Energy.period = Energy.kWhtoday; + Settings.energy_kWhtoday = Energy.kWhtoday; + RtcSettings.energy_kWhtoday = Energy.kWhtoday; + Energy.daily = (float)Energy.kWhtoday / 100000; + if (!RtcSettings.energy_kWhtotal && !Energy.kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); } break; case 2: Settings.energy_kWhyesterday = lnum *100; @@ -400,15 +404,15 @@ void CmndEnergyReset(void) case 3: RtcSettings.energy_kWhtotal = lnum *100; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; - energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; - Settings.energy_kWhtotal_time = (!energy_kWhtoday) ? LocalTime() : Midnight(); + Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000; + Settings.energy_kWhtotal_time = (!Energy.kWhtoday) ? LocalTime() : Midnight(); break; } } char energy_total_chr[33]; - dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr); + dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr); char energy_daily_chr[33]; - dtostrfd(energy_daily, Settings.flag2.energy_resolution, energy_daily_chr); + dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr); char energy_yesterday_chr[33]; dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); @@ -419,7 +423,7 @@ void CmndEnergyReset(void) void CmndPowerCal(void) { - energy_command_code = CMND_POWERCAL; + Energy.command_code = CMND_POWERCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_power_calibration = XdrvMailbox.payload; @@ -430,7 +434,7 @@ void CmndPowerCal(void) void CmndVoltageCal(void) { - energy_command_code = CMND_VOLTAGECAL; + Energy.command_code = CMND_VOLTAGECAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_voltage_calibration = XdrvMailbox.payload; @@ -441,7 +445,7 @@ void CmndVoltageCal(void) void CmndCurrentCal(void) { - energy_command_code = CMND_CURRENTCAL; + Energy.command_code = CMND_CURRENTCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { Settings.energy_current_calibration = XdrvMailbox.payload; @@ -452,7 +456,7 @@ void CmndCurrentCal(void) void CmndPowerSet(void) { - energy_command_code = CMND_POWERSET; + Energy.command_code = CMND_POWERSET; if (XnrgCall(FUNC_COMMAND)) { // Watt EnergyCommandResponse(Settings.energy_power_calibration, UNIT_MILLISECOND); } @@ -460,7 +464,7 @@ void CmndPowerSet(void) void CmndVoltageSet(void) { - energy_command_code = CMND_VOLTAGESET; + Energy.command_code = CMND_VOLTAGESET; if (XnrgCall(FUNC_COMMAND)) { // Volt EnergyCommandResponse(Settings.energy_voltage_calibration, UNIT_MILLISECOND); } @@ -468,7 +472,7 @@ void CmndVoltageSet(void) void CmndCurrentSet(void) { - energy_command_code = CMND_CURRENTSET; + Energy.command_code = CMND_CURRENTSET; if (XnrgCall(FUNC_COMMAND)) { // milliAmpere EnergyCommandResponse(Settings.energy_current_calibration, UNIT_MILLISECOND); } @@ -476,7 +480,7 @@ void CmndCurrentSet(void) void CmndFrequencySet(void) { - energy_command_code = CMND_FREQUENCYSET; + Energy.command_code = CMND_FREQUENCYSET; if (XnrgCall(FUNC_COMMAND)) { // Hz EnergyCommandResponse(Settings.energy_frequency_calibration, UNIT_MILLISECOND); } @@ -592,7 +596,7 @@ void CmndMaxEnergy(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { Settings.energy_max_energy = XdrvMailbox.payload; - energy_max_energy_state = 3; + Energy.max_energy_state = 3; } EnergyCommandResponse(Settings.energy_max_energy, UNIT_WATTHOUR); } @@ -618,9 +622,9 @@ void EnergySnsInit(void) XnrgCall(FUNC_INIT); if (energy_flg) { - energy_kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0; - energy_kWhtoday_delta = 0; - energy_period = energy_kWhtoday; + Energy.kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0; + Energy.kWhtoday_delta = 0; + Energy.period = Energy.kWhtoday; EnergyUpdateToday(); ticker_energy.attach_ms(200, Energy200ms); } @@ -645,35 +649,35 @@ void EnergyShow(bool json) bool show_energy_period = (0 == tele_period); - float power_factor = energy_power_factor; + float power_factor = Energy.power_factor; char apparent_power_chr[33]; char reactive_power_chr[33]; char power_factor_chr[33]; char frequency_chr[33]; - if (!energy_type_dc) { - if (energy_current_available && energy_voltage_available) { - float apparent_power = energy_apparent_power; + if (!Energy.type_dc) { + if (Energy.current_available && Energy.voltage_available) { + float apparent_power = Energy.apparent_power; if (isnan(apparent_power)) { - apparent_power = energy_voltage * energy_current; + apparent_power = Energy.voltage * Energy.current; } - if (apparent_power < energy_active_power) { // Should be impossible - energy_active_power = apparent_power; + if (apparent_power < Energy.active_power) { // Should be impossible + Energy.active_power = apparent_power; } if (isnan(power_factor)) { - power_factor = (energy_active_power && apparent_power) ? energy_active_power / apparent_power : 0; + power_factor = (Energy.active_power && apparent_power) ? Energy.active_power / apparent_power : 0; if (power_factor > 1) power_factor = 1; } - float reactive_power = energy_reactive_power; + float reactive_power = Energy.reactive_power; if (isnan(reactive_power)) { reactive_power = 0; - uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(energy_active_power * 100)) / 10; - if ((energy_current > 0.005) && ((difference > 15) || (difference > (uint32_t)(apparent_power * 100 / 1000)))) { + uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(Energy.active_power * 100)) / 10; + if ((Energy.current > 0.005) && ((difference > 15) || (difference > (uint32_t)(apparent_power * 100 / 1000)))) { // calculating reactive power only if current is greater than 0.005A and // difference between active and apparent power is greater than 1.5W or 1% - reactive_power = (float)(RoundSqrtInt((uint32_t)(apparent_power * apparent_power * 100) - (uint32_t)(energy_active_power * energy_active_power * 100))) / 10; + reactive_power = (float)(RoundSqrtInt((uint32_t)(apparent_power * apparent_power * 100) - (uint32_t)(Energy.active_power * Energy.active_power * 100))) / 10; } } @@ -681,29 +685,29 @@ void EnergyShow(bool json) dtostrfd(reactive_power, Settings.flag2.wattage_resolution, reactive_power_chr); dtostrfd(power_factor, 2, power_factor_chr); } - if (!isnan(energy_frequency)) { - dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, frequency_chr); + if (!isnan(Energy.frequency)) { + dtostrfd(Energy.frequency, Settings.flag2.frequency_resolution, frequency_chr); } } char voltage_chr[33]; - dtostrfd(energy_voltage, Settings.flag2.voltage_resolution, voltage_chr); + dtostrfd(Energy.voltage, Settings.flag2.voltage_resolution, voltage_chr); char current_chr[33]; - dtostrfd(energy_current, Settings.flag2.current_resolution, current_chr); + dtostrfd(Energy.current, Settings.flag2.current_resolution, current_chr); char active_power_chr[33]; - dtostrfd(energy_active_power, Settings.flag2.wattage_resolution, active_power_chr); + dtostrfd(Energy.active_power, Settings.flag2.wattage_resolution, active_power_chr); char energy_daily_chr[33]; - dtostrfd(energy_daily, Settings.flag2.energy_resolution, energy_daily_chr); + dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr); char energy_yesterday_chr[33]; dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); char energy_total_chr[33]; - dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr); + dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr); float energy = 0; char energy_period_chr[33]; if (show_energy_period) { - if (energy_period) energy = (float)(energy_kWhtoday - energy_period) / 100; - energy_period = energy_kWhtoday; + if (Energy.period) energy = (float)(Energy.kWhtoday - Energy.period) / 100; + Energy.period = Energy.kWhtoday; dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr); snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_JSON_PERIOD "\":%s"), energy_period_chr); } @@ -711,64 +715,64 @@ void EnergyShow(bool json) if (json) { ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" D_JSON_POWERUSAGE "\":%s"), GetDateAndTime(DT_ENERGY).c_str(), energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", active_power_chr); - if (!energy_type_dc) { - if (energy_current_available && energy_voltage_available) { + if (!Energy.type_dc) { + if (Energy.current_available && Energy.voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), apparent_power_chr, reactive_power_chr, power_factor_chr); } - if (!isnan(energy_frequency)) { + if (!isnan(Energy.frequency)) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), frequency_chr); } } - if (energy_voltage_available) { + if (Energy.voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), voltage_chr); } - if (energy_current_available) { + if (Energy.current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), current_chr); } ResponseJsonEnd(); #ifdef USE_DOMOTICZ if (show_energy_period) { // Only send if telemetry - dtostrfd(energy_total * 1000, 1, energy_total_chr); - DomoticzSensorPowerEnergy((int)energy_active_power, energy_total_chr); // PowerUsage, EnergyToday - if (energy_voltage_available) { + dtostrfd(Energy.total * 1000, 1, energy_total_chr); + DomoticzSensorPowerEnergy((int)Energy.active_power, energy_total_chr); // PowerUsage, EnergyToday + if (Energy.voltage_available) { DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage } - if (energy_current_available) { + if (Energy.current_available) { DomoticzSensor(DZ_CURRENT, current_chr); // Current } } #endif // USE_DOMOTICZ #ifdef USE_KNX if (show_energy_period) { - if (energy_voltage_available) { - KnxSensor(KNX_ENERGY_VOLTAGE, energy_voltage); + if (Energy.voltage_available) { + KnxSensor(KNX_ENERGY_VOLTAGE, Energy.voltage); } - if (energy_current_available) { - KnxSensor(KNX_ENERGY_CURRENT, energy_current); + if (Energy.current_available) { + KnxSensor(KNX_ENERGY_CURRENT, Energy.current); } - KnxSensor(KNX_ENERGY_POWER, energy_active_power); - if (!energy_type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); } - KnxSensor(KNX_ENERGY_DAILY, energy_daily); - KnxSensor(KNX_ENERGY_TOTAL, energy_total); - KnxSensor(KNX_ENERGY_START, energy_start); + KnxSensor(KNX_ENERGY_POWER, Energy.active_power); + if (!Energy.type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); } + KnxSensor(KNX_ENERGY_DAILY, Energy.daily); + KnxSensor(KNX_ENERGY_TOTAL, Energy.total); + KnxSensor(KNX_ENERGY_START, Energy.start_energy); } #endif // USE_KNX #ifdef USE_WEBSERVER } else { - if (energy_voltage_available) { + if (Energy.voltage_available) { WSContentSend_PD(PSTR("{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"), voltage_chr); } - if (energy_current_available) { + if (Energy.current_available) { WSContentSend_PD(PSTR("{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"), current_chr); } WSContentSend_PD(PSTR("{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"), active_power_chr); - if (!energy_type_dc) { - if (energy_current_available && energy_voltage_available) { + if (!Energy.type_dc) { + if (Energy.current_available && Energy.voltage_available) { WSContentSend_PD(HTTP_ENERGY_SNS1, apparent_power_chr, reactive_power_chr, power_factor_chr); } - if (!isnan(energy_frequency)) { + if (!isnan(Energy.frequency)) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), frequency_chr); } } @@ -795,7 +799,7 @@ bool Xdrv03(uint8_t function) break; #ifdef USE_ENERGY_MARGIN_DETECTION case FUNC_SET_POWER: - energy_power_steady_cntr = 2; + Energy.power_steady_counter = 2; break; #endif // USE_ENERGY_MARGIN_DETECTION case FUNC_SERIAL: diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 73f31c91f..befa9c305 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -41,33 +41,35 @@ #define HLW_SAMPLE_COUNT 10 // Max number of samples per cycle //#define HLW_DEBUG + +struct HLW { #ifdef HLW_DEBUG -unsigned long hlw_debug[HLW_SAMPLE_COUNT]; + unsigned long debug[HLW_SAMPLE_COUNT]; #endif + unsigned long cf_pulse_length = 0; + unsigned long cf_pulse_last_time = 0; + unsigned long cf_power_pulse_length = 0; -unsigned long hlw_cf_pulse_length = 0; -unsigned long hlw_cf_pulse_last_time = 0; -unsigned long hlw_cf_power_pulse_length = 0; + unsigned long cf1_pulse_length = 0; + unsigned long cf1_pulse_last_time = 0; + unsigned long cf1_summed_pulse_length = 0; + unsigned long cf1_pulse_counter = 0; + unsigned long cf1_voltage_pulse_length = 0; + unsigned long cf1_current_pulse_length = 0; -unsigned long hlw_cf1_pulse_length = 0; -unsigned long hlw_cf1_pulse_last_time = 0; -unsigned long hlw_cf1_summed_pulse_length = 0; -unsigned long hlw_cf1_pulse_counter = 0; -unsigned long hlw_cf1_voltage_pulse_length = 0; -unsigned long hlw_cf1_current_pulse_length = 0; + unsigned long energy_period_counter = 0; -unsigned long hlw_energy_period_counter = 0; + unsigned long power_ratio = 0; + unsigned long voltage_ratio = 0; + unsigned long current_ratio = 0; -unsigned long hlw_power_ratio = 0; -unsigned long hlw_voltage_ratio = 0; -unsigned long hlw_current_ratio = 0; - -uint8_t hlw_select_ui_flag = 0; -uint8_t hlw_ui_flag = 1; -uint8_t hlw_model_type = 0; -uint8_t hlw_load_off = 1; -uint8_t hlw_cf1_timer = 0; -uint8_t hlw_power_retry = 0; + uint8_t model_type = 0; + uint8_t cf1_timer = 0; + uint8_t power_retry = 0; + bool select_ui_flag = false; + bool ui_flag = true; + bool load_off = true; +} Hlw; // Fix core 2.5.x ISR not in IRAM Exception #ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception @@ -79,34 +81,34 @@ void HlwCfInterrupt(void) // Service Power { unsigned long us = micros(); - if (hlw_load_off) { // Restart plen measurement - hlw_cf_pulse_last_time = us; - hlw_load_off = 0; + if (Hlw.load_off) { // Restart plen measurement + Hlw.cf_pulse_last_time = us; + Hlw.load_off = false; } else { - hlw_cf_pulse_length = us - hlw_cf_pulse_last_time; - hlw_cf_pulse_last_time = us; - hlw_energy_period_counter++; + Hlw.cf_pulse_length = us - Hlw.cf_pulse_last_time; + Hlw.cf_pulse_last_time = us; + Hlw.energy_period_counter++; } - energy_data_valid = 0; + Energy.data_valid = 0; } void HlwCf1Interrupt(void) // Service Voltage and Current { unsigned long us = micros(); - hlw_cf1_pulse_length = us - hlw_cf1_pulse_last_time; - hlw_cf1_pulse_last_time = us; - if ((hlw_cf1_timer > 2) && (hlw_cf1_timer < 8)) { // Allow for 300 mSec set-up time and measure for up to 1 second - hlw_cf1_summed_pulse_length += hlw_cf1_pulse_length; + Hlw.cf1_pulse_length = us - Hlw.cf1_pulse_last_time; + Hlw.cf1_pulse_last_time = us; + if ((Hlw.cf1_timer > 2) && (Hlw.cf1_timer < 8)) { // Allow for 300 mSec set-up time and measure for up to 1 second + Hlw.cf1_summed_pulse_length += Hlw.cf1_pulse_length; #ifdef HLW_DEBUG - hlw_debug[hlw_cf1_pulse_counter] = hlw_cf1_pulse_length; + Hlw.debug[Hlw.cf1_pulse_counter] = Hlw.cf1_pulse_length; #endif - hlw_cf1_pulse_counter++; - if (HLW_SAMPLE_COUNT == hlw_cf1_pulse_counter) { - hlw_cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second) + Hlw.cf1_pulse_counter++; + if (HLW_SAMPLE_COUNT == Hlw.cf1_pulse_counter) { + Hlw.cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second) } } - energy_data_valid = 0; + Energy.data_valid = 0; } /********************************************************************************************/ @@ -118,97 +120,97 @@ void HlwEvery200ms(void) unsigned long hlw_u = 0; unsigned long hlw_i = 0; - if (micros() - hlw_cf_pulse_last_time > (HLW_POWER_PROBE_TIME * 1000000)) { - hlw_cf_pulse_length = 0; // No load for some time - hlw_load_off = 1; + if (micros() - Hlw.cf_pulse_last_time > (HLW_POWER_PROBE_TIME * 1000000)) { + Hlw.cf_pulse_length = 0; // No load for some time + Hlw.load_off = true; } - hlw_cf_power_pulse_length = hlw_cf_pulse_length; + Hlw.cf_power_pulse_length = Hlw.cf_pulse_length; - if (hlw_cf_power_pulse_length && energy_power_on && !hlw_load_off) { - hlw_w = (hlw_power_ratio * Settings.energy_power_calibration) / hlw_cf_power_pulse_length; // W *10 - energy_active_power = (float)hlw_w / 10; - hlw_power_retry = 1; // Workaround issue #5161 + if (Hlw.cf_power_pulse_length && Energy.power_on && !Hlw.load_off) { + hlw_w = (Hlw.power_ratio * Settings.energy_power_calibration) / Hlw.cf_power_pulse_length ; // W *10 + Energy.active_power = (float)hlw_w / 10; + Hlw.power_retry = 1; // Workaround issue #5161 } else { - if (hlw_power_retry) { - hlw_power_retry--; + if (Hlw.power_retry) { + Hlw.power_retry--; } else { - energy_active_power = 0; + Energy.active_power = 0; } } if (pin[GPIO_NRG_CF1] < 99) { - hlw_cf1_timer++; - if (hlw_cf1_timer >= 8) { - hlw_cf1_timer = 0; - hlw_select_ui_flag = (hlw_select_ui_flag) ? 0 : 1; + Hlw.cf1_timer++; + if (Hlw.cf1_timer >= 8) { + Hlw.cf1_timer = 0; + Hlw.select_ui_flag = (Hlw.select_ui_flag) ? false : true; if (pin[GPIO_NRG_SEL] < 99) { - digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); + digitalWrite(pin[GPIO_NRG_SEL], Hlw.select_ui_flag); } - if (hlw_cf1_pulse_counter) { - cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter; + if (Hlw.cf1_pulse_counter) { + cf1_pulse_length = Hlw.cf1_summed_pulse_length / Hlw.cf1_pulse_counter; } #ifdef HLW_DEBUG // Debugging for calculating mean and median char stemp[100]; stemp[0] = '\0'; - for (uint32_t i = 0; i < hlw_cf1_pulse_counter; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%s %d"), stemp, hlw_debug[i]); + for (uint32_t i = 0; i < Hlw.cf1_pulse_counter; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%s %d"), stemp, Hlw.debug[i]); } - for (uint32_t i = 0; i < hlw_cf1_pulse_counter; i++) { - for (uint32_t j = i + 1; j < hlw_cf1_pulse_counter; j++) { - if (hlw_debug[i] > hlw_debug[j]) { // Sort ascending - std::swap(hlw_debug[i], hlw_debug[j]); + for (uint32_t i = 0; i < Hlw.cf1_pulse_counter; i++) { + for (uint32_t j = i + 1; j < Hlw.cf1_pulse_counter; j++) { + if (Hlw.debug[i] > Hlw.debug[j]) { // Sort ascending + std::swap(Hlw.debug[i], Hlw.debug[j]); } } } - unsigned long median = hlw_debug[(hlw_cf1_pulse_counter +1) / 2]; + unsigned long median = Hlw.debug[(Hlw.cf1_pulse_counter +1) / 2]; AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: power %d, ui %d, cnt %d, smpl%s, sum %d, mean %d, median %d"), - hlw_cf_power_pulse_length, hlw_select_ui_flag, hlw_cf1_pulse_counter, stemp, hlw_cf1_summed_pulse_length, cf1_pulse_length, median); + Hlw.cf_power_pulse_length , Hlw.select_ui_flag, Hlw.cf1_pulse_counter, stemp, Hlw.cf1_summed_pulse_length, cf1_pulse_length, median); #endif - if (hlw_select_ui_flag == hlw_ui_flag) { - hlw_cf1_voltage_pulse_length = cf1_pulse_length; + if (Hlw.select_ui_flag == Hlw.ui_flag) { + Hlw.cf1_voltage_pulse_length = cf1_pulse_length; - if (hlw_cf1_voltage_pulse_length && energy_power_on) { // If powered on always provide voltage - hlw_u = (hlw_voltage_ratio * Settings.energy_voltage_calibration) / hlw_cf1_voltage_pulse_length; // V *10 - energy_voltage = (float)hlw_u / 10; + if (Hlw.cf1_voltage_pulse_length && Energy.power_on) { // If powered on always provide voltage + hlw_u = (Hlw.voltage_ratio * Settings.energy_voltage_calibration) / Hlw.cf1_voltage_pulse_length ; // V *10 + Energy.voltage = (float)hlw_u / 10; } else { - energy_voltage = 0; + Energy.voltage = 0; } } else { - hlw_cf1_current_pulse_length = cf1_pulse_length; + Hlw.cf1_current_pulse_length = cf1_pulse_length; - if (hlw_cf1_current_pulse_length && energy_active_power) { // No current if no power being consumed - hlw_i = (hlw_current_ratio * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length; // mA - energy_current = (float)hlw_i / 1000; + if (Hlw.cf1_current_pulse_length && Energy.active_power) { // No current if no power being consumed + hlw_i = (Hlw.current_ratio * Settings.energy_current_calibration) / Hlw.cf1_current_pulse_length; // mA + Energy.current = (float)hlw_i / 1000; } else { - energy_current = 0; + Energy.current = 0; } } - hlw_cf1_summed_pulse_length = 0; - hlw_cf1_pulse_counter = 0; + Hlw.cf1_summed_pulse_length = 0; + Hlw.cf1_pulse_counter = 0; } } } void HlwEverySecond(void) { - if (energy_data_valid > ENERGY_WATCHDOG) { - hlw_cf1_voltage_pulse_length = 0; - hlw_cf1_current_pulse_length = 0; - hlw_cf_power_pulse_length = 0; + if (Energy.data_valid > ENERGY_WATCHDOG) { + Hlw.cf1_voltage_pulse_length = 0; + Hlw.cf1_current_pulse_length = 0; + Hlw.cf_power_pulse_length = 0; } else { unsigned long hlw_len; - if (hlw_energy_period_counter) { - hlw_len = 10000 / hlw_energy_period_counter; - hlw_energy_period_counter = 0; + if (Hlw.energy_period_counter) { + hlw_len = 10000 / Hlw.energy_period_counter; + Hlw.energy_period_counter = 0; if (hlw_len) { - energy_kWhtoday_delta += ((hlw_power_ratio * Settings.energy_power_calibration) / hlw_len) / 36; + Energy.kWhtoday_delta += ((Hlw.power_ratio * Settings.energy_power_calibration) / hlw_len) / 36; EnergyUpdateToday(); } } @@ -223,19 +225,19 @@ void HlwSnsInit(void) Settings.energy_current_calibration = HLW_IREF_PULSE; } - if (hlw_model_type) { - hlw_power_ratio = HJL_PREF; - hlw_voltage_ratio = HJL_UREF; - hlw_current_ratio = HJL_IREF; + if (Hlw.model_type) { + Hlw.power_ratio = HJL_PREF; + Hlw.voltage_ratio = HJL_UREF; + Hlw.current_ratio = HJL_IREF; } else { - hlw_power_ratio = HLW_PREF; - hlw_voltage_ratio = HLW_UREF; - hlw_current_ratio = HLW_IREF; + Hlw.power_ratio = HLW_PREF; + Hlw.voltage_ratio = HLW_UREF; + Hlw.current_ratio = HLW_IREF; } if (pin[GPIO_NRG_SEL] < 99) { pinMode(pin[GPIO_NRG_SEL], OUTPUT); - digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); + digitalWrite(pin[GPIO_NRG_SEL], Hlw.select_ui_flag); } if (pin[GPIO_NRG_CF1] < 99) { pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP); @@ -248,29 +250,29 @@ void HlwSnsInit(void) void HlwDrvInit(void) { if (!energy_flg) { - hlw_model_type = 0; // HLW8012 + Hlw.model_type = 0; // HLW8012 if (pin[GPIO_HJL_CF] < 99) { pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; pin[GPIO_HJL_CF] = 99; - hlw_model_type = 1; // HJL-01/BL0937 + Hlw.model_type = 1; // HJL-01/BL0937 } if (pin[GPIO_HLW_CF] < 99) { // HLW8012 or HJL-01 based device Power monitor - hlw_ui_flag = 1; // Voltage on high + Hlw.ui_flag = true; // Voltage on high if (pin[GPIO_NRG_SEL_INV] < 99) { pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; pin[GPIO_NRG_SEL_INV] = 99; - hlw_ui_flag = 0; // Voltage on low + Hlw.ui_flag = false; // Voltage on low } if (pin[GPIO_NRG_CF1] < 99) { // Voltage and/or Current monitor if (99 == pin[GPIO_NRG_SEL]) { // Voltage and/or Current selector - energy_current_available = false; // Assume Voltage + Energy.current_available = false; // Assume Voltage } } else { - energy_current_available = false; - energy_voltage_available = false; + Energy.current_available = false; + Energy.voltage_available = false; } energy_flg = XNRG_01; @@ -282,22 +284,22 @@ bool HlwCommand(void) { bool serviced = true; - if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { + if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) { // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == energy_command_code) { - if (XdrvMailbox.data_len && hlw_cf_power_pulse_length) { - Settings.energy_power_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * hlw_cf_power_pulse_length) / hlw_power_ratio; + else if (CMND_POWERSET == Energy.command_code) { + if (XdrvMailbox.data_len && Hlw.cf_power_pulse_length ) { + Settings.energy_power_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio; } } - else if (CMND_VOLTAGESET == energy_command_code) { - if (XdrvMailbox.data_len && hlw_cf1_voltage_pulse_length) { - Settings.energy_voltage_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * hlw_cf1_voltage_pulse_length) / hlw_voltage_ratio; + else if (CMND_VOLTAGESET == Energy.command_code) { + if (XdrvMailbox.data_len && Hlw.cf1_voltage_pulse_length ) { + Settings.energy_voltage_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio; } } - else if (CMND_CURRENTSET == energy_command_code) { - if (XdrvMailbox.data_len && hlw_cf1_current_pulse_length) { - Settings.energy_current_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data)) * hlw_cf1_current_pulse_length) / hlw_current_ratio; + else if (CMND_CURRENTSET == Energy.command_code) { + if (XdrvMailbox.data_len && Hlw.cf1_current_pulse_length) { + Settings.energy_current_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio; } } else serviced = false; // Unknown command diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index f9d6d81e2..f5e1a606c 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -37,15 +37,17 @@ #define CSE_PREF 1000 #define CSE_UREF 100 -uint8_t cse_receive_flag = 0; +struct CSE { + long voltage_cycle = 0; + long current_cycle = 0; + long power_cycle = 0; + long power_cycle_first = 0; + long cf_pulses = 0; + long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; -long voltage_cycle = 0; -long current_cycle = 0; -long power_cycle = 0; -long power_cycle_first = 0; -long cf_pulses = 0; -long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; -uint8_t cse_power_invalid = 0; + uint8_t power_invalid = 0; + bool received = false; +} Cse; void CseReceived(void) { @@ -84,54 +86,54 @@ void CseReceived(void) } uint8_t adjustement = serial_in_buffer[20]; - voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7]; - current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13]; - power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19]; - cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22]; + Cse.voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7]; + Cse.current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13]; + Cse.power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19]; + Cse.cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22]; - if (energy_power_on) { // Powered on + if (Energy.power_on) { // Powered on if (adjustement & 0x40) { // Voltage valid - energy_voltage = (float)(Settings.energy_voltage_calibration * CSE_UREF) / (float)voltage_cycle; + Energy.voltage = (float)(Settings.energy_voltage_calibration * CSE_UREF) / (float)Cse.voltage_cycle; } if (adjustement & 0x10) { // Power valid - cse_power_invalid = 0; + Cse.power_invalid = 0; if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range - energy_active_power = 0; + Energy.active_power = 0; } else { - if (0 == power_cycle_first) { power_cycle_first = power_cycle; } // Skip first incomplete power_cycle - if (power_cycle_first != power_cycle) { - power_cycle_first = -1; - energy_active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle; + if (0 == Cse.power_cycle_first) { Cse.power_cycle_first = Cse.power_cycle; } // Skip first incomplete Cse.power_cycle + if (Cse.power_cycle_first != Cse.power_cycle) { + Cse.power_cycle_first = -1; + Energy.active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle; } else { - energy_active_power = 0; + Energy.active_power = 0; } } } else { - if (cse_power_invalid < Settings.param[P_CSE7766_INVALID_POWER]) { // Allow measurements down to about 1W - cse_power_invalid++; + if (Cse.power_invalid < Settings.param[P_CSE7766_INVALID_POWER]) { // Allow measurements down to about 1W + Cse.power_invalid++; } else { - power_cycle_first = 0; - energy_active_power = 0; // Powered on but no load + Cse.power_cycle_first = 0; + Energy.active_power = 0; // Powered on but no load } } if (adjustement & 0x20) { // Current valid - if (0 == energy_active_power) { - energy_current = 0; + if (0 == Energy.active_power) { + Energy.current = 0; } else { - energy_current = (float)Settings.energy_current_calibration / (float)current_cycle; + Energy.current = (float)Settings.energy_current_calibration / (float)Cse.current_cycle; } } } else { // Powered off - power_cycle_first = 0; - energy_voltage = 0; - energy_active_power = 0; - energy_current = 0; + Cse.power_cycle_first = 0; + Energy.voltage = 0; + Energy.active_power = 0; + Energy.current = 0; } } bool CseSerialInput(void) { - if (cse_receive_flag) { + if (Cse.received) { serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; if (24 == serial_in_byte_counter) { @@ -140,9 +142,9 @@ bool CseSerialInput(void) uint8_t checksum = 0; for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; } if (checksum == serial_in_buffer[23]) { - energy_data_valid = 0; + Energy.data_valid = 0; CseReceived(); - cse_receive_flag = 0; + Cse.received = false; return 1; } else { AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE)); @@ -151,14 +153,14 @@ bool CseSerialInput(void) serial_in_byte_counter--; } while ((serial_in_byte_counter > 2) && (0x5A != serial_in_buffer[1])); if (0x5A != serial_in_buffer[1]) { - cse_receive_flag = 0; + Cse.received = false; serial_in_byte_counter = 0; } } } } else { if ((0x5A == serial_in_byte) && (1 == serial_in_byte_counter)) { // 0x5A - Packet header 2 - cse_receive_flag = 1; + Cse.received = true; } else { serial_in_byte_counter = 0; } @@ -172,31 +174,31 @@ bool CseSerialInput(void) void CseEverySecond(void) { - if (energy_data_valid > ENERGY_WATCHDOG) { - voltage_cycle = 0; - current_cycle = 0; - power_cycle = 0; + if (Energy.data_valid > ENERGY_WATCHDOG) { + Cse.voltage_cycle = 0; + Cse.current_cycle = 0; + Cse.power_cycle = 0; } else { long cf_frequency = 0; - if (CSE_PULSES_NOT_INITIALIZED == cf_pulses_last_time) { - cf_pulses_last_time = cf_pulses; // Init after restart + if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) { + Cse.cf_pulses_last_time = Cse.cf_pulses; // Init after restart } else { - if (cf_pulses < cf_pulses_last_time) { // Rolled over after 65535 pulses - cf_frequency = (65536 - cf_pulses_last_time) + cf_pulses; + if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 65535 pulses + cf_frequency = (65536 - Cse.cf_pulses_last_time) + Cse.cf_pulses; } else { - cf_frequency = cf_pulses - cf_pulses_last_time; + cf_frequency = Cse.cf_pulses - Cse.cf_pulses_last_time; } - if (cf_frequency && energy_active_power) { + if (cf_frequency && Energy.active_power) { unsigned long delta = (cf_frequency * Settings.energy_power_calibration) / 36; // prevent invalid load delta steps even checksum is valid (issue #5789): if (delta <= (3680*100/36) * 10 ) { // max load for S31/Pow R2: 3.68kW - cf_pulses_last_time = cf_pulses; - energy_kWhtoday_delta += delta; + Cse.cf_pulses_last_time = Cse.cf_pulses; + Energy.kWhtoday_delta += delta; } else { AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow")); - cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; + Cse.cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; } EnergyUpdateToday(); } @@ -213,7 +215,7 @@ void CseDrvInit(void) if (0 == Settings.param[P_CSE7766_INVALID_POWER]) { Settings.param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } - cse_power_invalid = Settings.param[P_CSE7766_INVALID_POWER]; + Cse.power_invalid = Settings.param[P_CSE7766_INVALID_POWER]; energy_flg = XNRG_02; } } @@ -223,19 +225,19 @@ bool CseCommand(void) { bool serviced = true; - if (CMND_POWERSET == energy_command_code) { - if (XdrvMailbox.data_len && power_cycle) { - Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * power_cycle) / CSE_PREF; + if (CMND_POWERSET == Energy.command_code) { + if (XdrvMailbox.data_len && Cse.power_cycle) { + Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; } } - else if (CMND_VOLTAGESET == energy_command_code) { - if (XdrvMailbox.data_len && voltage_cycle) { - Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; + else if (CMND_VOLTAGESET == Energy.command_code) { + if (XdrvMailbox.data_len && Cse.voltage_cycle) { + Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF; } } - else if (CMND_CURRENTSET == energy_command_code) { - if (XdrvMailbox.data_len && current_cycle) { - Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * current_cycle) / 1000; + else if (CMND_CURRENTSET == Energy.command_code) { + if (XdrvMailbox.data_len && Cse.current_cycle) { + Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000; } } else serviced = false; // Unknown command diff --git a/sonoff/xnrg_03_pzem004t.ino b/sonoff/xnrg_03_pzem004t.ino index 1e5d0723b..4083d9b38 100644 --- a/sonoff/xnrg_03_pzem004t.ino +++ b/sonoff/xnrg_03_pzem004t.ino @@ -169,22 +169,22 @@ void PzemEvery200ms(void) if (data_ready) { float value = 0; if (PzemRecieve(pzem_responses[pzem_read_state], &value)) { - energy_data_valid = 0; + Energy.data_valid = 0; switch (pzem_read_state) { case 1: // Voltage as 230.2V - energy_voltage = value; + Energy.voltage = value; break; case 2: // Current as 17.32A - energy_current = value; + Energy.current = value; break; case 3: // Power as 20W - energy_active_power = value; + Energy.active_power = value; break; case 4: // Total energy as 99999Wh - if (!energy_start || (value < energy_start)) energy_start = value; // Init after restart and hanlde roll-over if any - if (value != energy_start) { - energy_kWhtoday += (unsigned long)((value - energy_start) * 100); - energy_start = value; + if (!Energy.start_energy || (value < Energy.start_energy)) Energy.start_energy = value; // Init after restart and hanlde roll-over if any + if (value != Energy.start_energy) { + Energy.kWhtoday += (unsigned long)((value - Energy.start_energy) * 100); + Energy.start_energy = value; } EnergyUpdateToday(); break; diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index 6171ef93a..5cdb4a50b 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -454,22 +454,22 @@ void McpParseData(void) // mcp_power_factor = McpExtractInt(mcp_buffer, 20, 2); mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2); - if (energy_power_on) { // Powered on - energy_frequency = (float)mcp_line_frequency / 1000; - energy_voltage = (float)mcp_voltage_rms / 10; - energy_active_power = (float)mcp_active_power / 100; - if (0 == energy_active_power) { - energy_current = 0; + if (Energy.power_on) { // Powered on + Energy.frequency = (float)mcp_line_frequency / 1000; + Energy.voltage = (float)mcp_voltage_rms / 10; + Energy.active_power = (float)mcp_active_power / 100; + if (0 == Energy.active_power) { + Energy.current = 0; } else { - energy_current = (float)mcp_current_rms / 10000; + Energy.current = (float)mcp_current_rms / 10000; } } else { // Powered off - energy_frequency = 0; - energy_voltage = 0; - energy_active_power = 0; - energy_current = 0; + Energy.frequency = 0; + Energy.voltage = 0; + Energy.active_power = 0; + Energy.current = 0; } - energy_data_valid = 0; + Energy.data_valid = 0; } /********************************************************************************************/ @@ -527,7 +527,7 @@ void McpSerialInput(void) void McpEverySecond(void) { - if (energy_data_valid > ENERGY_WATCHDOG) { + if (Energy.data_valid > ENERGY_WATCHDOG) { mcp_voltage_rms = 0; mcp_current_rms = 0; mcp_active_power = 0; @@ -535,7 +535,7 @@ void McpEverySecond(void) } if (mcp_active_power) { - energy_kWhtoday_delta += ((mcp_active_power * 10) / 36); + Energy.kWhtoday_delta += ((mcp_active_power * 10) / 36); EnergyUpdateToday(); } @@ -602,7 +602,7 @@ bool McpCommand(void) bool serviced = true; unsigned long value = 0; - if (CMND_POWERSET == energy_command_code) { + if (CMND_POWERSET == Energy.command_code) { if (XdrvMailbox.data_len && mcp_active_power) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100); if ((value > 100) && (value < 200000)) { // Between 1W and 2000W @@ -612,7 +612,7 @@ bool McpCommand(void) } } } - else if (CMND_VOLTAGESET == energy_command_code) { + else if (CMND_VOLTAGESET == Energy.command_code) { if (XdrvMailbox.data_len && mcp_voltage_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 1000) && (value < 2600)) { // Between 100V and 260V @@ -622,7 +622,7 @@ bool McpCommand(void) } } } - else if (CMND_CURRENTSET == energy_command_code) { + else if (CMND_CURRENTSET == Energy.command_code) { if (XdrvMailbox.data_len && mcp_current_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 100) && (value < 80000)) { // Between 10mA and 8A @@ -632,7 +632,7 @@ bool McpCommand(void) } } } - else if (CMND_FREQUENCYSET == energy_command_code) { + else if (CMND_FREQUENCYSET == Energy.command_code) { if (XdrvMailbox.data_len && mcp_line_frequency) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000); if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz diff --git a/sonoff/xnrg_05_pzem_ac.ino b/sonoff/xnrg_05_pzem_ac.ino index f23b22172..79f97e508 100644 --- a/sonoff/xnrg_05_pzem_ac.ino +++ b/sonoff/xnrg_05_pzem_ac.ino @@ -70,22 +70,22 @@ void PzemAcEverySecond(void) AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error); } else { // if ((PzemCalculateCRC(buffer, 23)) == ((buffer[24] << 8) | buffer[23])) { - energy_data_valid = 0; + Energy.data_valid = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34 // Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc-- - energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V - energy_current = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A - energy_active_power = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W - energy_frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz - energy_power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00 + Energy.voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V + Energy.current = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A + Energy.active_power = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W + Energy.frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz + Energy.power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00 float energy = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); // 4294967295 Wh - if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and handle roll-over if any - if (energy != energy_start) { - energy_kWhtoday += (unsigned long)((energy - energy_start) * 100); - energy_start = energy; + if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any + if (energy != Energy.start_energy) { + Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100); + Energy.start_energy = energy; } EnergyUpdateToday(); // } diff --git a/sonoff/xnrg_06_pzem_dc.ino b/sonoff/xnrg_06_pzem_dc.ino index ab70b4e62..4c8db837d 100644 --- a/sonoff/xnrg_06_pzem_dc.ino +++ b/sonoff/xnrg_06_pzem_dc.ino @@ -51,20 +51,20 @@ void PzemDcEverySecond(void) if (error) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error); } else { - energy_data_valid = 0; + Energy.data_valid = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29 // Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc-- - energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V - energy_current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A - energy_active_power = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W + Energy.voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V + Energy.current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A + Energy.active_power = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W float energy = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); // 4294967295 Wh - if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and handle roll-over if any - if (energy != energy_start) { - energy_kWhtoday += (unsigned long)((energy - energy_start) * 100); - energy_start = energy; + if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any + if (energy != Energy.start_energy) { + Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100); + Energy.start_energy = energy; } EnergyUpdateToday(); } @@ -85,7 +85,7 @@ void PzemDcSnsInit(void) uint8_t result = PzemDcModbus->Begin(9600, 2); // Uses two stop bits!! if (result) { if (2 == result) { ClaimSerial(); } - energy_type_dc = true; + Energy.type_dc = true; } else { energy_flg = ENERGY_NONE; } diff --git a/sonoff/xnrg_07_ade7953.ino b/sonoff/xnrg_07_ade7953.ino index 12635050b..de865f0e5 100644 --- a/sonoff/xnrg_07_ade7953.ino +++ b/sonoff/xnrg_07_ade7953.ino @@ -36,14 +36,16 @@ #define ADE7953_ADDR 0x38 -uint32_t ade7953_active_power = 0; -uint32_t ade7953_active_power1 = 0; -uint32_t ade7953_active_power2 = 0; -uint32_t ade7953_current_rms = 0; -uint32_t ade7953_current_rms1 = 0; -uint32_t ade7953_current_rms2 = 0; -uint32_t ade7953_voltage_rms = 0; -uint8_t ade7953_init = 0; +struct Ade7953 { + uint32_t active_power = 0; + uint32_t active_power1 = 0; + uint32_t active_power2 = 0; + uint32_t current_rms = 0; + uint32_t current_rms1 = 0; + uint32_t current_rms2 = 0; + uint32_t voltage_rms = 0; + uint8_t init_step = 0; +} Ade7953; int Ade7953RegSize(uint16_t reg) { @@ -109,57 +111,57 @@ void Ade7953GetData(void) { int32_t active_power; - ade7953_voltage_rms = Ade7953Read(0x31C); // Both relays - ade7953_current_rms1 = Ade7953Read(0x31B); // Relay 1 - if (ade7953_current_rms1 < 2000) { // No load threshold (20mA) - ade7953_current_rms1 = 0; - ade7953_active_power1 = 0; + Ade7953.voltage_rms = Ade7953Read(0x31C); // Both relays + Ade7953.current_rms1 = Ade7953Read(0x31B); // Relay 1 + if (Ade7953.current_rms1 < 2000) { // No load threshold (20mA) + Ade7953.current_rms1 = 0; + Ade7953.active_power1 = 0; } else { active_power = (int32_t)Ade7953Read(0x313) * -1; // Relay 1 - ade7953_active_power1 = (active_power > 0) ? active_power : 0; + Ade7953.active_power1 = (active_power > 0) ? active_power : 0; } - ade7953_current_rms2 = Ade7953Read(0x31A); // Relay 2 - if (ade7953_current_rms2 < 2000) { // No load threshold (20mA) - ade7953_current_rms2 = 0; - ade7953_active_power2 = 0; + Ade7953.current_rms2 = Ade7953Read(0x31A); // Relay 2 + if (Ade7953.current_rms2 < 2000) { // No load threshold (20mA) + Ade7953.current_rms2 = 0; + Ade7953.active_power2 = 0; } else { active_power = (int32_t)Ade7953Read(0x312); // Relay 2 - ade7953_active_power2 = (active_power > 0) ? active_power : 0; + Ade7953.active_power2 = (active_power > 0) ? active_power : 0; } // First phase only supports accumulated Current and Power - ade7953_current_rms = ade7953_current_rms1 + ade7953_current_rms2; - ade7953_active_power = ade7953_active_power1 + ade7953_active_power2; + Ade7953.current_rms = Ade7953.current_rms1 + Ade7953.current_rms2; + Ade7953.active_power = Ade7953.active_power1 + Ade7953.active_power2; AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ADE: U %d, I %d + %d = %d, P %d + %d = %d"), - ade7953_voltage_rms, ade7953_current_rms1, ade7953_current_rms2, ade7953_current_rms, ade7953_active_power1, ade7953_active_power2, ade7953_active_power); + Ade7953.voltage_rms, Ade7953.current_rms1, Ade7953.current_rms2, Ade7953.current_rms, Ade7953.active_power1, Ade7953.active_power2, Ade7953.active_power); - if (energy_power_on) { // Powered on - energy_voltage = (float)ade7953_voltage_rms / Settings.energy_voltage_calibration; - energy_active_power = (float)ade7953_active_power / (Settings.energy_power_calibration / 10); - if (0 == energy_active_power) { - energy_current = 0; + if (Energy.power_on) { // Powered on + Energy.voltage = (float)Ade7953.voltage_rms / Settings.energy_voltage_calibration; + Energy.active_power = (float)Ade7953.active_power / (Settings.energy_power_calibration / 10); + if (0 == Energy.active_power) { + Energy.current = 0; } else { - energy_current = (float)ade7953_current_rms / (Settings.energy_current_calibration * 10); + Energy.current = (float)Ade7953.current_rms / (Settings.energy_current_calibration * 10); } } else { // Powered off - energy_voltage = 0; - energy_active_power = 0; - energy_current = 0; + Energy.voltage = 0; + Energy.active_power = 0; + Energy.current = 0; } - if (ade7953_active_power) { - energy_kWhtoday_delta += ((ade7953_active_power * (100000 / (Settings.energy_power_calibration / 10))) / 3600); + if (Ade7953.active_power) { + Energy.kWhtoday_delta += ((Ade7953.active_power * (100000 / (Settings.energy_power_calibration / 10))) / 3600); EnergyUpdateToday(); } } void Ade7953EnergyEverySecond() { - if (ade7953_init) { - if (1 == ade7953_init) { + if (Ade7953.init_step) { + if (1 == Ade7953.init_step) { Ade7953Init(); } - ade7953_init--; + Ade7953.init_step--; } else { Ade7953GetData(); } @@ -177,7 +179,7 @@ void Ade7953DrvInit(void) Settings.energy_current_calibration = ADE7953_IREF; } AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADE7953", ADE7953_ADDR); - ade7953_init = 2; + Ade7953.init_step = 2; energy_flg = XNRG_07; } } @@ -190,36 +192,36 @@ bool Ade7953Command(void) uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 - if (CMND_POWERCAL == energy_command_code) { + if (CMND_POWERCAL == Energy.command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; } // Service in xdrv_03_energy.ino } - else if (CMND_VOLTAGECAL == energy_command_code) { + else if (CMND_VOLTAGECAL == Energy.command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_UREF; } // Service in xdrv_03_energy.ino } - else if (CMND_CURRENTCAL == energy_command_code) { + else if (CMND_CURRENTCAL == Energy.command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_IREF; } // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == energy_command_code) { - if (XdrvMailbox.data_len && ade7953_active_power) { + else if (CMND_POWERSET == Energy.command_code) { + if (XdrvMailbox.data_len && Ade7953.active_power) { if ((value > 100) && (value < 200000)) { // Between 1W and 2000W - Settings.energy_power_calibration = (ade7953_active_power * 1000) / value; // 0.00 W + Settings.energy_power_calibration = (Ade7953.active_power * 1000) / value; // 0.00 W } } } - else if (CMND_VOLTAGESET == energy_command_code) { - if (XdrvMailbox.data_len && ade7953_voltage_rms) { + else if (CMND_VOLTAGESET == Energy.command_code) { + if (XdrvMailbox.data_len && Ade7953.voltage_rms) { if ((value > 10000) && (value < 26000)) { // Between 100V and 260V - Settings.energy_voltage_calibration = (ade7953_voltage_rms * 100) / value; // 0.00 V + Settings.energy_voltage_calibration = (Ade7953.voltage_rms * 100) / value; // 0.00 V } } } - else if (CMND_CURRENTSET == energy_command_code) { - if (XdrvMailbox.data_len && ade7953_current_rms) { + else if (CMND_CURRENTSET == Energy.command_code) { + if (XdrvMailbox.data_len && Ade7953.current_rms) { if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A - Settings.energy_current_calibration = ((ade7953_current_rms * 100) / value) * 100; // 0.00 mA + Settings.energy_current_calibration = ((Ade7953.current_rms * 100) / value) * 100; // 0.00 mA } } } From 9746489380b26bd20064275226a319748398260d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 16:12:33 +0200 Subject: [PATCH 4/8] Bump version to 6.6.0.5 * Add command WebSensor 0/1 to control display of sensor data in web GUI (#6085) * Change some table locations from RAM to Flash --- sonoff/_changelog.ino | 4 + sonoff/settings.h | 2 +- sonoff/sonoff.h | 2 +- sonoff/sonoff_version.h | 2 +- sonoff/support_command.ino | 14 +- sonoff/xsns_interface.ino | 406 +++++++++++++++++++++++++++++++++++++ sonoff/zzzz_debug.ino | 250 ----------------------- 7 files changed, 425 insertions(+), 255 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 3690798cb..4e79481de 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,8 @@ /*********************************************************************************************\ + * 6.6.0.5 20190816 + * Add command WebSensor 0/1 to control display of sensor data in web GUI (#6085) + * Change some table locations from RAM to Flash + * * 6.6.0.4 20190806 * Add support for CHIRP soil moisture sensor by Christian Baars * Add debug compile features using defines DEBUG_TASMOTA_CORE, DEBUG_TASMOTA_DRIVER and DEBUG_TASMOTA_SENSOR. diff --git a/sonoff/settings.h b/sonoff/settings.h index 11e200a99..99591d6bf 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -344,7 +344,7 @@ struct SYSCFG { uint32_t adc_param2; // 798 int adc_param3; // 79C uint32_t monitors; // 7A0 - uint32_t sensors[3]; // 7A4 + uint32_t sensors[3]; // 7A4 Normal WebSensor, Debug SetSensor uint32_t displays; // 7B0 uint32_t energy_kWhtotal_time; // 7B4 unsigned long weight_item; // 7B8 Weight of one item in gram * 10 diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 3912fee45..e44b32b7a 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -24,7 +24,7 @@ * Performance ROM (PROGMEM) vs RAM (RODATA) \*********************************************************************************************/ -//#define XFUNC_PTR_IN_ROM // Enable for keeping tables in ROM (PROGMEM) which seem to have access issues on some flash types +#define XFUNC_PTR_IN_ROM // Enable for keeping tables in ROM (PROGMEM) which seem to have access issues on some flash types /*********************************************************************************************\ * Default sensor states diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 043193241..474ae4581 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,6 +20,6 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -const uint32_t VERSION = 0x06060004; +const uint32_t VERSION = 0x06060005; #endif // _SONOFF_VERSION_H_ diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index de7d9a60d..b69a144cc 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -30,7 +30,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix #ifdef USE_I2C D_CMND_I2CSCAN "|" #endif - D_CMND_SENSOR "|" D_CMND_DRIVER; + D_CMND_SENSOR "|" D_CMND_DRIVER "|WebSensor"; void (* const TasmotaCommand[])(void) PROGMEM = { &CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, @@ -45,7 +45,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { #ifdef USE_I2C &CmndI2cScan, #endif - &CmndSensor, &CmndDriver }; + &CmndSensor, &CmndDriver, &CmndWebSensor }; /********************************************************************************************/ @@ -662,6 +662,16 @@ void CmndSetoption(void) } } +void CmndWebSensor(void) +{ + if (XdrvMailbox.index < MAX_XSNS_DRIVERS) { + if (XdrvMailbox.payload >= 0) { + bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); + } + ResponseCmndIdxChar(GetStateText(bitRead(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32))); + } +} + void CmndTemperatureResolution(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 9d4d87c46..229fa63be 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -422,6 +422,410 @@ bool (* const xsns_func_ptr[])(uint8_t) = { // Sensor Function Pointers for sim const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); // Number of External Sensors found +/*********************************************************************************************\ + * Xsns available list +\*********************************************************************************************/ + +#ifdef XFUNC_PTR_IN_ROM +const uint8_t kXsnsList[] PROGMEM = { +#else +const uint8_t kXsnsList[] = { +#endif + +#ifdef XSNS_01 + XSNS_01, +#endif + +#ifdef XSNS_02 + XSNS_02, +#endif + +#ifdef XSNS_03 + XSNS_03, +#endif + +#ifdef XSNS_04 + XSNS_04, +#endif + +#ifdef XSNS_05 + XSNS_05, +#endif + +#ifdef XSNS_06 + XSNS_06, +#endif + +#ifdef XSNS_07 + XSNS_07, +#endif + +#ifdef XSNS_08 + XSNS_08, +#endif + +#ifdef XSNS_09 + XSNS_09, +#endif + +#ifdef XSNS_10 + XSNS_10, +#endif + +#ifdef XSNS_11 + XSNS_11, +#endif + +#ifdef XSNS_12 + XSNS_12, +#endif + +#ifdef XSNS_13 + XSNS_13, +#endif + +#ifdef XSNS_14 + XSNS_14, +#endif + +#ifdef XSNS_15 + XSNS_15, +#endif + +#ifdef XSNS_16 + XSNS_16, +#endif + +#ifdef XSNS_17 + XSNS_17, +#endif + +#ifdef XSNS_18 + XSNS_18, +#endif + +#ifdef XSNS_19 + XSNS_19, +#endif + +#ifdef XSNS_20 + XSNS_20, +#endif + +#ifdef XSNS_21 + XSNS_21, +#endif + +#ifdef XSNS_22 + XSNS_22, +#endif + +#ifdef XSNS_23 + XSNS_23, +#endif + +#ifdef XSNS_24 + XSNS_24, +#endif + +#ifdef XSNS_25 + XSNS_25, +#endif + +#ifdef XSNS_26 + XSNS_26, +#endif + +#ifdef XSNS_27 + XSNS_27, +#endif + +#ifdef XSNS_28 + XSNS_28, +#endif + +#ifdef XSNS_29 + XSNS_29, +#endif + +#ifdef XSNS_30 + XSNS_30, +#endif + +#ifdef XSNS_31 + XSNS_31, +#endif + +#ifdef XSNS_32 + XSNS_32, +#endif + +#ifdef XSNS_33 + XSNS_33, +#endif + +#ifdef XSNS_34 + XSNS_34, +#endif + +#ifdef XSNS_35 + XSNS_35, +#endif + +#ifdef XSNS_36 + XSNS_36, +#endif + +#ifdef XSNS_37 + XSNS_37, +#endif + +#ifdef XSNS_38 + XSNS_38, +#endif + +#ifdef XSNS_39 + XSNS_39, +#endif + +#ifdef XSNS_40 + XSNS_40, +#endif + +#ifdef XSNS_41 + XSNS_41, +#endif + +#ifdef XSNS_42 + XSNS_42, +#endif + +#ifdef XSNS_43 + XSNS_43, +#endif + +#ifdef XSNS_44 + XSNS_44, +#endif + +#ifdef XSNS_45 + XSNS_45, +#endif + +#ifdef XSNS_46 + XSNS_46, +#endif + +#ifdef XSNS_47 + XSNS_47, +#endif + +#ifdef XSNS_48 + XSNS_48, +#endif + +#ifdef XSNS_49 + XSNS_49, +#endif + +#ifdef XSNS_50 + XSNS_50, +#endif + +#ifdef XSNS_51 + XSNS_51, +#endif + +#ifdef XSNS_52 + XSNS_52, +#endif + +#ifdef XSNS_53 + XSNS_53, +#endif + +#ifdef XSNS_54 + XSNS_54, +#endif + +#ifdef XSNS_55 + XSNS_55, +#endif + +#ifdef XSNS_56 + XSNS_56, +#endif + +#ifdef XSNS_57 + XSNS_57, +#endif + +#ifdef XSNS_58 + XSNS_58, +#endif + +#ifdef XSNS_59 + XSNS_59, +#endif + +#ifdef XSNS_60 + XSNS_60, +#endif + +#ifdef XSNS_61 + XSNS_61, +#endif + +#ifdef XSNS_62 + XSNS_62, +#endif + +#ifdef XSNS_63 + XSNS_63, +#endif + +#ifdef XSNS_64 + XSNS_64, +#endif + +#ifdef XSNS_65 + XSNS_65, +#endif + +#ifdef XSNS_66 + XSNS_66, +#endif + +#ifdef XSNS_67 + XSNS_67, +#endif + +#ifdef XSNS_68 + XSNS_68, +#endif + +#ifdef XSNS_69 + XSNS_69, +#endif + +#ifdef XSNS_70 + XSNS_70, +#endif + +#ifdef XSNS_71 + XSNS_71, +#endif + +#ifdef XSNS_72 + XSNS_72, +#endif + +#ifdef XSNS_73 + XSNS_73, +#endif + +#ifdef XSNS_74 + XSNS_74, +#endif + +#ifdef XSNS_75 + XSNS_75, +#endif + +#ifdef XSNS_76 + XSNS_76, +#endif + +#ifdef XSNS_77 + XSNS_77, +#endif + +#ifdef XSNS_78 + XSNS_78, +#endif + +#ifdef XSNS_79 + XSNS_79, +#endif + +#ifdef XSNS_80 + XSNS_80, +#endif + +#ifdef XSNS_81 + XSNS_81, +#endif + +#ifdef XSNS_82 + XSNS_82, +#endif + +#ifdef XSNS_83 + XSNS_83, +#endif + +#ifdef XSNS_84 + XSNS_84, +#endif + +#ifdef XSNS_85 + XSNS_85, +#endif + +#ifdef XSNS_86 + XSNS_86, +#endif + +#ifdef XSNS_87 + XSNS_87, +#endif + +#ifdef XSNS_88 + XSNS_88, +#endif + +#ifdef XSNS_89 + XSNS_89, +#endif + +#ifdef XSNS_90 + XSNS_90, +#endif + +#ifdef XSNS_91 + XSNS_91, +#endif + +#ifdef XSNS_92 + XSNS_92, +#endif + +#ifdef XSNS_93 + XSNS_93, +#endif + +#ifdef XSNS_94 + XSNS_94, +#endif + +#ifdef XSNS_95 + XSNS_95 +#endif +}; + +bool XsnsEnabled(uint32_t sns_index) +{ + if (sns_index < sizeof(kXsnsList)) { +#ifdef XFUNC_PTR_IN_ROM + uint32_t index = pgm_read_byte(kXsnsList + sns_index); +#else + uint32_t index = kXsnsList[sns_index]; +#endif + return bitRead(Settings.sensors[index / 32], index % 32); + } + return true; +} + /*********************************************************************************************\ * Function call to all xsns \*********************************************************************************************/ @@ -453,6 +857,8 @@ bool XsnsCall(uint8_t Function) if (XsnsEnabled(x)) { #endif + if ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(x)) { continue; } // Skip web info for disabled sensors + #ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND uint32_t profile_start_millis = millis(); #endif // PROFILE_XSNS_SENSOR_EVERY_SECOND diff --git a/sonoff/zzzz_debug.ino b/sonoff/zzzz_debug.ino index 7b2e7e6ad..521418819 100644 --- a/sonoff/zzzz_debug.ino +++ b/sonoff/zzzz_debug.ino @@ -24,256 +24,6 @@ * Needs to be the last alphabetical file due to DEFINE compile order \*********************************************************************************************/ -/*********************************************************************************************\ - * Xsns available list -\*********************************************************************************************/ - -#ifdef XFUNC_PTR_IN_ROM -const uint8_t kXsnsList[] PROGMEM = { -#else -const uint8_t kXsnsList[] = { -#endif - -#ifdef XSNS_01 - XSNS_01, -#endif - -#ifdef XSNS_02 - XSNS_02, -#endif - -#ifdef XSNS_03 - XSNS_03, -#endif - -#ifdef XSNS_04 - XSNS_04, -#endif - -#ifdef XSNS_05 - XSNS_05, -#endif - -#ifdef XSNS_06 - XSNS_06, -#endif - -#ifdef XSNS_07 - XSNS_07, -#endif - -#ifdef XSNS_08 - XSNS_08, -#endif - -#ifdef XSNS_09 - XSNS_09, -#endif - -#ifdef XSNS_10 - XSNS_10, -#endif - -#ifdef XSNS_11 - XSNS_11, -#endif - -#ifdef XSNS_12 - XSNS_12, -#endif - -#ifdef XSNS_13 - XSNS_13, -#endif - -#ifdef XSNS_14 - XSNS_14, -#endif - -#ifdef XSNS_15 - XSNS_15, -#endif - -#ifdef XSNS_16 - XSNS_16, -#endif - -#ifdef XSNS_17 - XSNS_17, -#endif - -#ifdef XSNS_18 - XSNS_18, -#endif - -#ifdef XSNS_19 - XSNS_19, -#endif - -#ifdef XSNS_20 - XSNS_20, -#endif - -#ifdef XSNS_21 - XSNS_21, -#endif - -#ifdef XSNS_22 - XSNS_22, -#endif - -#ifdef XSNS_23 - XSNS_23, -#endif - -#ifdef XSNS_24 - XSNS_24, -#endif - -#ifdef XSNS_25 - XSNS_25, -#endif - -#ifdef XSNS_26 - XSNS_26, -#endif - -#ifdef XSNS_27 - XSNS_27, -#endif - -#ifdef XSNS_28 - XSNS_28, -#endif - -#ifdef XSNS_29 - XSNS_29, -#endif - -#ifdef XSNS_30 - XSNS_30, -#endif - -#ifdef XSNS_31 - XSNS_31, -#endif - -#ifdef XSNS_32 - XSNS_32, -#endif - -#ifdef XSNS_33 - XSNS_33, -#endif - -#ifdef XSNS_34 - XSNS_34, -#endif - -#ifdef XSNS_35 - XSNS_35, -#endif - -#ifdef XSNS_36 - XSNS_36, -#endif - -#ifdef XSNS_37 - XSNS_37, -#endif - -#ifdef XSNS_38 - XSNS_38, -#endif - -#ifdef XSNS_39 - XSNS_39, -#endif - -#ifdef XSNS_40 - XSNS_40, -#endif - -#ifdef XSNS_41 - XSNS_41, -#endif - -#ifdef XSNS_42 - XSNS_42, -#endif - -#ifdef XSNS_43 - XSNS_43, -#endif - -#ifdef XSNS_44 - XSNS_44, -#endif - -#ifdef XSNS_45 - XSNS_45, -#endif - -#ifdef XSNS_46 - XSNS_46, -#endif - -#ifdef XSNS_47 - XSNS_47, -#endif - -#ifdef XSNS_48 - XSNS_48, -#endif - -#ifdef XSNS_49 - XSNS_49, -#endif - -#ifdef XSNS_50 - XSNS_50, -#endif - -// Optional user defined sensors in range 91 - 99 - -#ifdef XSNS_91 - XSNS_91, -#endif - -#ifdef XSNS_92 - XSNS_92, -#endif - -#ifdef XSNS_93 - XSNS_93, -#endif - -#ifdef XSNS_94 - XSNS_94, -#endif - -#ifdef XSNS_95 - XSNS_95 -#endif -}; - -/*********************************************************************************************\ - * Xsns sensor control -\*********************************************************************************************/ - -bool XsnsEnabled(uint8_t sns_index) -{ - if (sns_index < sizeof(kXsnsList)) { -#ifdef XFUNC_PTR_IN_ROM - uint8_t index = pgm_read_byte(kXsnsList + sns_index); -#else - uint8_t index = kXsnsList[sns_index]; -#endif - return bitRead(Settings.sensors[index / 32], index % 32); - } - return 1; -} - bool XsnsPresent(uint8_t sns_index) { uint8_t index = 0; From c61f2cc5ec481ed1bbb44d96fad952509f5ac3ba Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 16:54:36 +0200 Subject: [PATCH 5/8] Refactor WebSensor Refactor WebSensor --- sonoff/i18n.h | 1 + sonoff/support_command.ino | 14 ++------------ sonoff/xdrv_01_webserver.ino | 14 ++++++++++++-- sonoff/xsns_interface.ino | 2 ++ 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index f61d3d40a..cb68dcd4c 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -324,6 +324,7 @@ #define D_CMND_WEBREFRESH "WebRefresh" #define D_CMND_WEBSEND "WebSend" #define D_CMND_WEBCOLOR "WebColor" +#define D_CMND_WEBSENSOR "WebSensor" #define D_CMND_EMULATION "Emulation" // Commands xdrv_03_energy.ino diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index b69a144cc..de7d9a60d 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -30,7 +30,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix #ifdef USE_I2C D_CMND_I2CSCAN "|" #endif - D_CMND_SENSOR "|" D_CMND_DRIVER "|WebSensor"; + D_CMND_SENSOR "|" D_CMND_DRIVER; void (* const TasmotaCommand[])(void) PROGMEM = { &CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, @@ -45,7 +45,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { #ifdef USE_I2C &CmndI2cScan, #endif - &CmndSensor, &CmndDriver, &CmndWebSensor }; + &CmndSensor, &CmndDriver }; /********************************************************************************************/ @@ -662,16 +662,6 @@ void CmndSetoption(void) } } -void CmndWebSensor(void) -{ - if (XdrvMailbox.index < MAX_XSNS_DRIVERS) { - if (XdrvMailbox.payload >= 0) { - bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); - } - ResponseCmndIdxChar(GetStateText(bitRead(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32))); - } -} - void CmndTemperatureResolution(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index f11480c58..0589c52f0 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -2460,13 +2460,13 @@ const char kWebCommands[] PROGMEM = "|" // No prefix #ifdef USE_EMULATION D_CMND_EMULATION "|" #endif - D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR ; + D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_WEBSENSOR; void (* const WebCommand[])(void) PROGMEM = { #ifdef USE_EMULATION &CmndEmulation, #endif - &CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor }; + &CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor }; /*********************************************************************************************\ * Commands @@ -2563,6 +2563,16 @@ void CmndWebColor(void) ResponseAppend_P(PSTR("]}")); } +void CmndWebSensor(void) +{ + if (XdrvMailbox.index < MAX_XSNS_DRIVERS) { + if (XdrvMailbox.payload >= 0) { + bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); + } + ResponseCmndIdxChar(GetStateText(bitRead(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32))); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 229fa63be..519dbf683 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -813,6 +813,8 @@ const uint8_t kXsnsList[] = { #endif }; +/*********************************************************************************************/ + bool XsnsEnabled(uint32_t sns_index) { if (sns_index < sizeof(kXsnsList)) { From b5f290b4a2bd77c866979a0b2d6971bb6c2cb7cf Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 17:29:19 +0200 Subject: [PATCH 6/8] Change display ledtable location from RAM to flash Change display ledtable location from RAM to flash --- sonoff/xdrv_04_light.ino | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index deb4d0109..7dd64dadc 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -174,7 +174,11 @@ const LCwColor kFixedColdWarm[MAX_FIXED_COLD_WARM] PROGMEM = { 0,0, 255,0, 0,255 // from 11 bits (lower values) to 8 bits (upper values). // We're using the fact that lower values are small and can fit within 8 bits // To save flash space, the array is only 8 bits uint +#ifdef XFUNC_PTR_IN_ROM +const uint8_t _ledTable[] PROGMEM = { +#else const uint8_t _ledTable[] = { +#endif // 11 bits resolution 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, // 11 bits, 0..2047 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, // 11 bits, 0..2047 @@ -997,7 +1001,11 @@ uint16_t ledGamma(uint8_t v, uint16_t bits_out = 8) { // bits_resolution: the resolution of _ledTable[v], between 8 and 11 uint32_t bits_resolution = 11 - (v / 64); // 8..11 int32_t bits_correction = bits_out - bits_resolution; // -3..3 +#ifdef XFUNC_PTR_IN_ROM + uint32_t uncorrected_value = pgm_read_byte(_ledTable + v); // 0..255 +#else uint32_t uncorrected_value = _ledTable[v]; // 0..255 +#endif if (0 == bits_correction) { // we already match the required resolution, no change result = uncorrected_value; From 26d331501becfc9090b4a5150e9645a79c6c8078 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 17:48:05 +0200 Subject: [PATCH 7/8] Add embedded sensor numbering to Status 4 Add embedded sensor numbering to Status 4 --- sonoff/support_command.ino | 4 ++-- sonoff/xsns_interface.ino | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index de7d9a60d..5dcbf0b8c 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -333,10 +333,10 @@ void CmndStatus(void) if ((0 == payload) || (4 == payload)) { Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\"" D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\"" - D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]}}"), + D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"],\"Sensors\":%s}}"), ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipId(), ESP.getFlashChipMode(), - LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5); + LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, XsnsSensorsAvailable().c_str()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4")); } diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 519dbf683..438591129 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -828,6 +828,22 @@ bool XsnsEnabled(uint32_t sns_index) return true; } +String XsnsSensorsAvailable() +{ + String sensors = F("["); + for (uint32_t i = 0; i < sizeof(kXsnsList); i++) { +#ifdef XFUNC_PTR_IN_ROM + uint32_t sensorid = pgm_read_byte(kXsnsList + i); +#else + uint32_t sensorid = kXsnsList[i]; +#endif + if (i) { sensors += F(","); } + sensors += String(sensorid); + } + sensors += F("]"); + return sensors; +} + /*********************************************************************************************\ * Function call to all xsns \*********************************************************************************************/ From 676c7867ca6b52f7d0212bd890262a12cead75e0 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Aug 2019 18:30:45 +0200 Subject: [PATCH 8/8] Refactor Sensors available Refactor Sensors available --- sonoff/support_command.ino | 3 ++- sonoff/xsns_interface.ino | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index 5dcbf0b8c..01c365213 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -331,12 +331,13 @@ void CmndStatus(void) } if ((0 == payload) || (4 == payload)) { + char sensors[LOGSZ]; Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\"" D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\"" D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"],\"Sensors\":%s}}"), ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipId(), ESP.getFlashChipMode(), - LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, XsnsSensorsAvailable().c_str()); + LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, XsnsSensorsAvailable(sensors)); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4")); } diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 438591129..57eaebb51 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -828,19 +828,19 @@ bool XsnsEnabled(uint32_t sns_index) return true; } -String XsnsSensorsAvailable() +char* XsnsSensorsAvailable(char* sensors) { - String sensors = F("["); + // Return string like [2,3,4,5,8,9,10,14,15,17,18,34] + sensors[0] = '\0'; for (uint32_t i = 0; i < sizeof(kXsnsList); i++) { #ifdef XFUNC_PTR_IN_ROM uint32_t sensorid = pgm_read_byte(kXsnsList + i); #else uint32_t sensorid = kXsnsList[i]; #endif - if (i) { sensors += F(","); } - sensors += String(sensorid); + snprintf_P(sensors, LOGSZ, PSTR("%s%s%d"), sensors, (!i) ? "[" : ",", sensorid); } - sensors += F("]"); + snprintf_P(sensors, LOGSZ, PSTR("%s]"), sensors); // Max length is about 3 x 96 < LOGSZ return sensors; }