Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into issue_6191

This commit is contained in:
Stephan Hadinger 2019-08-16 18:33:53 +02:00
commit 1de7abe9f4
21 changed files with 1026 additions and 709 deletions

View File

@ -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 copying a string to a number or reverse is supported
>**\>B** >**\>B**
executed on BOOT time executed on BOOT time and script save
>**\>T** >**\>T**
executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section 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 **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) **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 **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** names a subroutine, subroutines are called with **=#name**
**#name(param)** names a subroutines with a parameter is called with **=#name(param)** **#name(param)** names a subroutines with a parameter is called with **=#name(param)**

View File

@ -1,4 +1,8 @@
/*********************************************************************************************\ /*********************************************************************************************\
* 6.6.0.5 20190816
* Add command WebSensor<sensor number> 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 * 6.6.0.4 20190806
* Add support for CHIRP soil moisture sensor by Christian Baars * 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. * Add debug compile features using defines DEBUG_TASMOTA_CORE, DEBUG_TASMOTA_DRIVER and DEBUG_TASMOTA_SENSOR.

View File

@ -324,6 +324,7 @@
#define D_CMND_WEBREFRESH "WebRefresh" #define D_CMND_WEBREFRESH "WebRefresh"
#define D_CMND_WEBSEND "WebSend" #define D_CMND_WEBSEND "WebSend"
#define D_CMND_WEBCOLOR "WebColor" #define D_CMND_WEBCOLOR "WebColor"
#define D_CMND_WEBSENSOR "WebSensor"
#define D_CMND_EMULATION "Emulation" #define D_CMND_EMULATION "Emulation"
// Commands xdrv_03_energy.ino // Commands xdrv_03_energy.ino

View File

@ -344,7 +344,7 @@ struct SYSCFG {
uint32_t adc_param2; // 798 uint32_t adc_param2; // 798
int adc_param3; // 79C int adc_param3; // 79C
uint32_t monitors; // 7A0 uint32_t monitors; // 7A0
uint32_t sensors[3]; // 7A4 uint32_t sensors[3]; // 7A4 Normal WebSensor, Debug SetSensor
uint32_t displays; // 7B0 uint32_t displays; // 7B0
uint32_t energy_kWhtotal_time; // 7B4 uint32_t energy_kWhtotal_time; // 7B4
unsigned long weight_item; // 7B8 Weight of one item in gram * 10 unsigned long weight_item; // 7B8 Weight of one item in gram * 10

View File

@ -24,7 +24,7 @@
* Performance ROM (PROGMEM) vs RAM (RODATA) * 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 * Default sensor states

View File

@ -20,6 +20,6 @@
#ifndef _SONOFF_VERSION_H_ #ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_
const uint32_t VERSION = 0x06060004; const uint32_t VERSION = 0x06060005;
#endif // _SONOFF_VERSION_H_ #endif // _SONOFF_VERSION_H_

View File

@ -331,12 +331,13 @@ void CmndStatus(void)
} }
if ((0 == payload) || (4 == payload)) { 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,\"" 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_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.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024,
ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipId(), ESP.getFlashChipMode(), 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(sensors));
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4")); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4"));
} }

View File

@ -488,7 +488,6 @@ struct WEB {
uint8_t config_xor_on_set = CONFIG_FILE_XOR; uint8_t config_xor_on_set = CONFIG_FILE_XOR;
} Web; } Web;
// Helper function to avoid code duplication (saves 4k Flash) // Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg(const char* arg, char* out, size_t max) static void WebGetArg(const char* arg, char* out, size_t max)
{ {
@ -2461,13 +2460,13 @@ const char kWebCommands[] PROGMEM = "|" // No prefix
#ifdef USE_EMULATION #ifdef USE_EMULATION
D_CMND_EMULATION "|" D_CMND_EMULATION "|"
#endif #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 = { void (* const WebCommand[])(void) PROGMEM = {
#ifdef USE_EMULATION #ifdef USE_EMULATION
&CmndEmulation, &CmndEmulation,
#endif #endif
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor }; &CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor };
/*********************************************************************************************\ /*********************************************************************************************\
* Commands * Commands
@ -2564,6 +2563,16 @@ void CmndWebColor(void)
ResponseAppend_P(PSTR("]}")); 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 * Interface
\*********************************************************************************************/ \*********************************************************************************************/

View File

@ -67,94 +67,98 @@ void (* const EnergyCommand[])(void) PROGMEM = {
#endif // USE_ENERGY_MARGIN_DETECTION #endif // USE_ENERGY_MARGIN_DETECTION
&CmndEnergyReset }; &CmndEnergyReset };
float energy_voltage = 0; // 123.1 V struct ENERGY {
float energy_current = 0; // 123.123 A float voltage = 0; // 123.1 V
float energy_active_power = 0; // 123.1 W float current = 0; // 123.123 A
float energy_apparent_power = NAN; // 123.1 VA float active_power = 0; // 123.1 W
float energy_reactive_power = NAN; // 123.1 VAr float apparent_power = NAN; // 123.1 VA
float energy_power_factor = NAN; // 0.12 float reactive_power = NAN; // 123.1 VAr
float energy_frequency = NAN; // 123.1 Hz float power_factor = NAN; // 0.12
float energy_start = 0; // 12345.12345 kWh total previous float frequency = NAN; // 123.1 Hz
float start_energy = 0; // 12345.12345 kWh total previous
float energy_daily = 0; // 123.123 kWh float daily = 0; // 123.123 kWh
float energy_total = 0; // 12345.12345 kWh float 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
uint8_t energy_command_code = 0; unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
uint8_t energy_data_valid = 0; 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 uint8_t fifth_second = 0;
bool energy_current_available = true; // Enable if current is measured uint8_t command_code = 0;
uint8_t data_valid = 0;
bool energy_type_dc = false; bool voltage_available = true; // Enable if voltage is measured
bool energy_power_on = true; bool current_available = true; // Enable if current is measured
bool type_dc = false;
bool power_on = true;
#ifdef USE_ENERGY_MARGIN_DETECTION #ifdef USE_ENERGY_MARGIN_DETECTION
float energy_power_last[3] = { 0 }; float power_history[3] = { 0 };
uint8_t energy_power_delta = 0; uint8_t power_steady_counter = 8; // Allow for power on stabilization
bool energy_min_power_flag = false; uint8_t power_delta = 0;
bool energy_max_power_flag = false; bool min_power_flag = false;
bool energy_min_voltage_flag = false; bool max_power_flag = false;
bool energy_max_voltage_flag = false; bool min_voltage_flag = false;
bool energy_min_current_flag = false; bool max_voltage_flag = false;
bool energy_max_current_flag = false; bool min_current_flag = false;
uint8_t energy_power_steady_cntr = 8; // Allow for power on stabilization bool max_current_flag = false;
#ifdef USE_ENERGY_POWER_LIMIT #ifdef USE_ENERGY_POWER_LIMIT
uint16_t energy_mplh_counter = 0; uint16_t mplh_counter = 0;
uint16_t energy_mplw_counter = 0; uint16_t mplw_counter = 0;
uint8_t energy_mplr_counter = 0; uint8_t mplr_counter = 0;
uint8_t energy_max_energy_state = 0; uint8_t max_energy_state = 0;
#endif // USE_ENERGY_POWER_LIMIT #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; Ticker ticker_energy;
/********************************************************************************************/ /********************************************************************************************/
void EnergyUpdateToday(void) void EnergyUpdateToday(void)
{ {
if (energy_kWhtoday_delta > 1000) { if (Energy.kWhtoday_delta > 1000) {
unsigned long delta = energy_kWhtoday_delta / 1000; unsigned long delta = Energy.kWhtoday_delta / 1000;
energy_kWhtoday_delta -= (delta * 1000); Energy.kWhtoday_delta -= (delta * 1000);
energy_kWhtoday += delta; Energy.kWhtoday += delta;
} }
RtcSettings.energy_kWhtoday = energy_kWhtoday; RtcSettings.energy_kWhtoday = Energy.kWhtoday;
energy_daily = (float)energy_kWhtoday / 100000; Energy.daily = (float)Energy.kWhtoday / 100000;
energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000;
} }
/*********************************************************************************************/ /*********************************************************************************************/
void Energy200ms(void) 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++; Energy.fifth_second++;
if (5 == energy_fifth_second) { if (5 == Energy.fifth_second) {
energy_fifth_second = 0; Energy.fifth_second = 0;
XnrgCall(FUNC_ENERGY_EVERY_SECOND); XnrgCall(FUNC_ENERGY_EVERY_SECOND);
if (RtcTime.valid) { if (RtcTime.valid) {
if (LocalTime() == Midnight()) { if (LocalTime() == Midnight()) {
Settings.energy_kWhyesterday = energy_kWhtoday; Settings.energy_kWhyesterday = Energy.kWhtoday;
Settings.energy_kWhtotal += energy_kWhtoday; Settings.energy_kWhtotal += Energy.kWhtoday;
RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal; RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal;
energy_kWhtoday = 0; Energy.kWhtoday = 0;
energy_kWhtoday_delta = 0; Energy.kWhtoday_delta = 0;
energy_period = energy_kWhtoday; Energy.period = Energy.kWhtoday;
EnergyUpdateToday(); EnergyUpdateToday();
#if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) #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 #endif // USE_ENERGY_POWER_LIMIT
} }
#if defined(USE_ENERGY_MARGIN_DETECTION) && defined(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)) { if ((RtcTime.hour == Settings.energy_max_energy_start) && (3 == Energy.max_energy_state )) {
energy_max_energy_state = 0; Energy.max_energy_state = 0;
} }
#endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_POWER_LIMIT
@ -167,8 +171,8 @@ void Energy200ms(void)
void EnergySaveState(void) void EnergySaveState(void)
{ {
Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0;
Settings.energy_kWhtoday = energy_kWhtoday; Settings.energy_kWhtoday = Energy.kWhtoday;
RtcSettings.energy_kWhtoday = energy_kWhtoday; RtcSettings.energy_kWhtoday = Energy.kWhtoday;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
} }
@ -197,55 +201,55 @@ void EnergyMarginCheck(void)
bool flag; bool flag;
bool jsonflg; bool jsonflg;
if (energy_power_steady_cntr) { if (Energy.power_steady_counter) {
energy_power_steady_cntr--; Energy.power_steady_counter--;
return; return;
} }
if (Settings.energy_power_delta) { 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 // 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) { if (((delta / min_power) * 100) > Settings.energy_power_delta) {
energy_power_delta = 1; Energy.power_delta = 1;
energy_power_last[1] = energy_active_power; // We only want one report so reset history Energy.power_history[1] = Energy.active_power; // We only want one report so reset history
energy_power_last[2] = energy_active_power; 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_history[0] = Energy.power_history[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_history[1] = Energy.power_history[2];
energy_power_last[2] = energy_active_power; 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)) { 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_power_u = (uint16_t)(Energy.active_power);
energy_voltage_u = (uint16_t)(energy_voltage); energy_voltage_u = (uint16_t)(Energy.voltage);
energy_current_u = (uint16_t)(energy_current * 1000); 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); DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u);
Response_P(PSTR("{")); Response_P(PSTR("{"));
jsonflg = false; 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)); ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; 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)); ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; 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)); ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; 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)); ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; 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)); ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; 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)); ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
jsonflg = true; jsonflg = true;
} }
@ -259,35 +263,35 @@ void EnergyMarginCheck(void)
#ifdef USE_ENERGY_POWER_LIMIT #ifdef USE_ENERGY_POWER_LIMIT
// Max Power // Max Power
if (Settings.energy_max_power_limit) { if (Settings.energy_max_power_limit) {
if (energy_active_power > Settings.energy_max_power_limit) { if (Energy.active_power > Settings.energy_max_power_limit) {
if (!energy_mplh_counter) { if (!Energy.mplh_counter) {
energy_mplh_counter = Settings.energy_max_power_limit_hold; Energy.mplh_counter = Settings.energy_max_power_limit_hold;
} else { } else {
energy_mplh_counter--; Energy.mplh_counter--;
if (!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 : ""); Response_P(PSTR("{\"" D_JSON_MAXPOWERREACHED "\":\"%d%s\"}"), energy_power_u, (Settings.flag.value_units) ? " " D_UNIT_WATT : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow(); EnergyMqttShow();
ExecuteCommandPower(1, POWER_OFF, SRC_MAXPOWER); ExecuteCommandPower(1, POWER_OFF, SRC_MAXPOWER);
if (!energy_mplr_counter) { if (!Energy.mplr_counter) {
energy_mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1; 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)) { else if (power && (energy_power_u <= Settings.energy_max_power_limit)) {
energy_mplh_counter = 0; Energy.mplh_counter = 0;
energy_mplr_counter = 0; Energy.mplr_counter = 0;
energy_mplw_counter = 0; Energy.mplw_counter = 0;
} }
if (!power) { if (!power) {
if (energy_mplw_counter) { if (Energy.mplw_counter) {
energy_mplw_counter--; Energy.mplw_counter--;
} else { } else {
if (energy_mplr_counter) { if (Energy.mplr_counter) {
energy_mplr_counter--; Energy.mplr_counter--;
if (energy_mplr_counter) { if (Energy.mplr_counter) {
Response_P(PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1)); Response_P(PSTR("{\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR)); MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXPOWER); ExecuteCommandPower(1, POWER_ON, SRC_MAXPOWER);
@ -303,16 +307,16 @@ void EnergyMarginCheck(void)
// Max Energy // Max Energy
if (Settings.energy_max_energy) { if (Settings.energy_max_energy) {
energy_daily_u = (uint16_t)(energy_daily * 1000); energy_daily_u = (uint16_t)(Energy.daily * 1000);
if (!energy_max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) { if (!Energy.max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) {
energy_max_energy_state = 1; Energy.max_energy_state = 1;
Response_P(PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); Response_P(PSTR("{\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR));
ExecuteCommandPower(1, POWER_ON, SRC_MAXENERGY); ExecuteCommandPower(1, POWER_ON, SRC_MAXENERGY);
} }
else if ((1 == energy_max_energy_state) && (energy_daily_u >= Settings.energy_max_energy)) { else if ((1 == Energy.max_energy_state ) && (energy_daily_u >= Settings.energy_max_energy)) {
energy_max_energy_state = 2; Energy.max_energy_state = 2;
dtostrfd(energy_daily, 3, mqtt_data); dtostrfd(Energy.daily, 3, mqtt_data);
Response_P(PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : ""); Response_P(PSTR("{\"" D_JSON_MAXENERGYREACHED "\":\"%s%s\"}"), mqtt_data, (Settings.flag.value_units) ? " " D_UNIT_KILOWATTHOUR : "");
MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING);
EnergyMqttShow(); EnergyMqttShow();
@ -321,7 +325,7 @@ void EnergyMarginCheck(void)
} }
#endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_POWER_LIMIT
if (energy_power_delta) { EnergyMqttShow(); } if (Energy.power_delta) { EnergyMqttShow(); }
} }
void EnergyMqttShow(void) void EnergyMqttShow(void)
@ -334,7 +338,7 @@ void EnergyMqttShow(void)
tele_period = tele_period_save; tele_period = tele_period_save;
ResponseJsonEnd(); ResponseJsonEnd();
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); 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 #endif // USE_ENERGY_MARGIN_DETECTION
@ -345,16 +349,16 @@ void EnergyOverTempCheck()
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP); SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
} }
} }
if (energy_data_valid <= ENERGY_WATCHDOG) { if (Energy.data_valid <= ENERGY_WATCHDOG) {
energy_data_valid++; Energy.data_valid++;
if (energy_data_valid > ENERGY_WATCHDOG) { if (Energy.data_valid > ENERGY_WATCHDOG) {
// Reset energy registers // Reset energy registers
energy_voltage = 0; Energy.voltage = 0;
energy_current = 0; Energy.current = 0;
energy_active_power = 0; Energy.active_power = 0;
if (!isnan(energy_frequency)) { energy_frequency = 0; } if (!isnan(Energy.frequency)) { Energy.frequency = 0; }
if (!isnan(energy_power_factor)) { energy_power_factor = 0; } if (!isnan(Energy.power_factor)) { Energy.power_factor = 0; }
energy_start = 0; Energy.start_energy = 0;
} }
} }
} }
@ -386,13 +390,13 @@ void CmndEnergyReset(void)
if (p != XdrvMailbox.data) { if (p != XdrvMailbox.data) {
switch (XdrvMailbox.index) { switch (XdrvMailbox.index) {
case 1: case 1:
energy_kWhtoday = lnum *100; Energy.kWhtoday = lnum *100;
energy_kWhtoday_delta = 0; Energy.kWhtoday_delta = 0;
energy_period = energy_kWhtoday; Energy.period = Energy.kWhtoday;
Settings.energy_kWhtoday = energy_kWhtoday; Settings.energy_kWhtoday = Energy.kWhtoday;
RtcSettings.energy_kWhtoday = energy_kWhtoday; RtcSettings.energy_kWhtoday = Energy.kWhtoday;
energy_daily = (float)energy_kWhtoday / 100000; Energy.daily = (float)Energy.kWhtoday / 100000;
if (!RtcSettings.energy_kWhtotal && !energy_kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); } if (!RtcSettings.energy_kWhtotal && !Energy.kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); }
break; break;
case 2: case 2:
Settings.energy_kWhyesterday = lnum *100; Settings.energy_kWhyesterday = lnum *100;
@ -400,15 +404,15 @@ void CmndEnergyReset(void)
case 3: case 3:
RtcSettings.energy_kWhtotal = lnum *100; RtcSettings.energy_kWhtotal = lnum *100;
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday) / 100000;
Settings.energy_kWhtotal_time = (!energy_kWhtoday) ? LocalTime() : Midnight(); Settings.energy_kWhtotal_time = (!Energy.kWhtoday) ? LocalTime() : Midnight();
break; break;
} }
} }
char energy_total_chr[33]; 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]; 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]; char energy_yesterday_chr[33];
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
@ -419,7 +423,7 @@ void CmndEnergyReset(void)
void CmndPowerCal(void) void CmndPowerCal(void)
{ {
energy_command_code = CMND_POWERCAL; Energy.command_code = CMND_POWERCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds if (XnrgCall(FUNC_COMMAND)) { // microseconds
if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
Settings.energy_power_calibration = XdrvMailbox.payload; Settings.energy_power_calibration = XdrvMailbox.payload;
@ -430,7 +434,7 @@ void CmndPowerCal(void)
void CmndVoltageCal(void) void CmndVoltageCal(void)
{ {
energy_command_code = CMND_VOLTAGECAL; Energy.command_code = CMND_VOLTAGECAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds if (XnrgCall(FUNC_COMMAND)) { // microseconds
if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
Settings.energy_voltage_calibration = XdrvMailbox.payload; Settings.energy_voltage_calibration = XdrvMailbox.payload;
@ -441,7 +445,7 @@ void CmndVoltageCal(void)
void CmndCurrentCal(void) void CmndCurrentCal(void)
{ {
energy_command_code = CMND_CURRENTCAL; Energy.command_code = CMND_CURRENTCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds if (XnrgCall(FUNC_COMMAND)) { // microseconds
if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) {
Settings.energy_current_calibration = XdrvMailbox.payload; Settings.energy_current_calibration = XdrvMailbox.payload;
@ -452,7 +456,7 @@ void CmndCurrentCal(void)
void CmndPowerSet(void) void CmndPowerSet(void)
{ {
energy_command_code = CMND_POWERSET; Energy.command_code = CMND_POWERSET;
if (XnrgCall(FUNC_COMMAND)) { // Watt if (XnrgCall(FUNC_COMMAND)) { // Watt
EnergyCommandResponse(Settings.energy_power_calibration, UNIT_MILLISECOND); EnergyCommandResponse(Settings.energy_power_calibration, UNIT_MILLISECOND);
} }
@ -460,7 +464,7 @@ void CmndPowerSet(void)
void CmndVoltageSet(void) void CmndVoltageSet(void)
{ {
energy_command_code = CMND_VOLTAGESET; Energy.command_code = CMND_VOLTAGESET;
if (XnrgCall(FUNC_COMMAND)) { // Volt if (XnrgCall(FUNC_COMMAND)) { // Volt
EnergyCommandResponse(Settings.energy_voltage_calibration, UNIT_MILLISECOND); EnergyCommandResponse(Settings.energy_voltage_calibration, UNIT_MILLISECOND);
} }
@ -468,7 +472,7 @@ void CmndVoltageSet(void)
void CmndCurrentSet(void) void CmndCurrentSet(void)
{ {
energy_command_code = CMND_CURRENTSET; Energy.command_code = CMND_CURRENTSET;
if (XnrgCall(FUNC_COMMAND)) { // milliAmpere if (XnrgCall(FUNC_COMMAND)) { // milliAmpere
EnergyCommandResponse(Settings.energy_current_calibration, UNIT_MILLISECOND); EnergyCommandResponse(Settings.energy_current_calibration, UNIT_MILLISECOND);
} }
@ -476,7 +480,7 @@ void CmndCurrentSet(void)
void CmndFrequencySet(void) void CmndFrequencySet(void)
{ {
energy_command_code = CMND_FREQUENCYSET; Energy.command_code = CMND_FREQUENCYSET;
if (XnrgCall(FUNC_COMMAND)) { // Hz if (XnrgCall(FUNC_COMMAND)) { // Hz
EnergyCommandResponse(Settings.energy_frequency_calibration, UNIT_MILLISECOND); EnergyCommandResponse(Settings.energy_frequency_calibration, UNIT_MILLISECOND);
} }
@ -592,7 +596,7 @@ void CmndMaxEnergy(void)
{ {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
Settings.energy_max_energy = XdrvMailbox.payload; Settings.energy_max_energy = XdrvMailbox.payload;
energy_max_energy_state = 3; Energy.max_energy_state = 3;
} }
EnergyCommandResponse(Settings.energy_max_energy, UNIT_WATTHOUR); EnergyCommandResponse(Settings.energy_max_energy, UNIT_WATTHOUR);
} }
@ -618,9 +622,9 @@ void EnergySnsInit(void)
XnrgCall(FUNC_INIT); XnrgCall(FUNC_INIT);
if (energy_flg) { if (energy_flg) {
energy_kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0; Energy.kWhtoday = (RtcSettingsValid()) ? RtcSettings.energy_kWhtoday : (RtcTime.day_of_year == Settings.energy_kWhdoy) ? Settings.energy_kWhtoday : 0;
energy_kWhtoday_delta = 0; Energy.kWhtoday_delta = 0;
energy_period = energy_kWhtoday; Energy.period = Energy.kWhtoday;
EnergyUpdateToday(); EnergyUpdateToday();
ticker_energy.attach_ms(200, Energy200ms); ticker_energy.attach_ms(200, Energy200ms);
} }
@ -645,35 +649,35 @@ void EnergyShow(bool json)
bool show_energy_period = (0 == tele_period); 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 apparent_power_chr[33];
char reactive_power_chr[33]; char reactive_power_chr[33];
char power_factor_chr[33]; char power_factor_chr[33];
char frequency_chr[33]; char frequency_chr[33];
if (!energy_type_dc) { if (!Energy.type_dc) {
if (energy_current_available && energy_voltage_available) { if (Energy.current_available && Energy.voltage_available) {
float apparent_power = energy_apparent_power; float apparent_power = Energy.apparent_power;
if (isnan(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 if (apparent_power < Energy.active_power) { // Should be impossible
energy_active_power = apparent_power; Energy.active_power = apparent_power;
} }
if (isnan(power_factor)) { 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; if (power_factor > 1) power_factor = 1;
} }
float reactive_power = energy_reactive_power; float reactive_power = Energy.reactive_power;
if (isnan(reactive_power)) { if (isnan(reactive_power)) {
reactive_power = 0; reactive_power = 0;
uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(energy_active_power * 100)) / 10; 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)))) { 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 // 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% // 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(reactive_power, Settings.flag2.wattage_resolution, reactive_power_chr);
dtostrfd(power_factor, 2, power_factor_chr); dtostrfd(power_factor, 2, power_factor_chr);
} }
if (!isnan(energy_frequency)) { if (!isnan(Energy.frequency)) {
dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, frequency_chr); dtostrfd(Energy.frequency, Settings.flag2.frequency_resolution, frequency_chr);
} }
} }
char voltage_chr[33]; 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]; 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]; 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]; 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]; char energy_yesterday_chr[33];
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
char energy_total_chr[33]; 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; float energy = 0;
char energy_period_chr[33]; char energy_period_chr[33];
if (show_energy_period) { if (show_energy_period) {
if (energy_period) energy = (float)(energy_kWhtoday - energy_period) / 100; if (Energy.period) energy = (float)(Energy.kWhtoday - Energy.period) / 100;
energy_period = energy_kWhtoday; Energy.period = Energy.kWhtoday;
dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr); dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr);
snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_JSON_PERIOD "\":%s"), 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) { 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"), 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); 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.type_dc) {
if (energy_current_available && energy_voltage_available) { if (Energy.current_available && Energy.voltage_available) {
ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), 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); 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); 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); 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); ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), current_chr);
} }
ResponseJsonEnd(); ResponseJsonEnd();
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
if (show_energy_period) { // Only send if telemetry if (show_energy_period) { // Only send if telemetry
dtostrfd(energy_total * 1000, 1, energy_total_chr); dtostrfd(Energy.total * 1000, 1, energy_total_chr);
DomoticzSensorPowerEnergy((int)energy_active_power, energy_total_chr); // PowerUsage, EnergyToday DomoticzSensorPowerEnergy((int)Energy.active_power, energy_total_chr); // PowerUsage, EnergyToday
if (energy_voltage_available) { if (Energy.voltage_available) {
DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage
} }
if (energy_current_available) { if (Energy.current_available) {
DomoticzSensor(DZ_CURRENT, current_chr); // Current DomoticzSensor(DZ_CURRENT, current_chr); // Current
} }
} }
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
#ifdef USE_KNX #ifdef USE_KNX
if (show_energy_period) { if (show_energy_period) {
if (energy_voltage_available) { if (Energy.voltage_available) {
KnxSensor(KNX_ENERGY_VOLTAGE, energy_voltage); KnxSensor(KNX_ENERGY_VOLTAGE, Energy.voltage);
} }
if (energy_current_available) { if (Energy.current_available) {
KnxSensor(KNX_ENERGY_CURRENT, energy_current); KnxSensor(KNX_ENERGY_CURRENT, Energy.current);
} }
KnxSensor(KNX_ENERGY_POWER, energy_active_power); KnxSensor(KNX_ENERGY_POWER, Energy.active_power);
if (!energy_type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); } if (!Energy.type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); }
KnxSensor(KNX_ENERGY_DAILY, energy_daily); KnxSensor(KNX_ENERGY_DAILY, Energy.daily);
KnxSensor(KNX_ENERGY_TOTAL, energy_total); KnxSensor(KNX_ENERGY_TOTAL, Energy.total);
KnxSensor(KNX_ENERGY_START, energy_start); KnxSensor(KNX_ENERGY_START, Energy.start_energy);
} }
#endif // USE_KNX #endif // USE_KNX
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
} else { } else {
if (energy_voltage_available) { if (Energy.voltage_available) {
WSContentSend_PD(PSTR("{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"), voltage_chr); 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_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"), current_chr);
} }
WSContentSend_PD(PSTR("{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"), active_power_chr); WSContentSend_PD(PSTR("{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"), active_power_chr);
if (!energy_type_dc) { if (!Energy.type_dc) {
if (energy_current_available && energy_voltage_available) { if (Energy.current_available && Energy.voltage_available) {
WSContentSend_PD(HTTP_ENERGY_SNS1, apparent_power_chr, reactive_power_chr, power_factor_chr); 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); WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), frequency_chr);
} }
} }
@ -795,7 +799,7 @@ bool Xdrv03(uint8_t function)
break; break;
#ifdef USE_ENERGY_MARGIN_DETECTION #ifdef USE_ENERGY_MARGIN_DETECTION
case FUNC_SET_POWER: case FUNC_SET_POWER:
energy_power_steady_cntr = 2; Energy.power_steady_counter = 2;
break; break;
#endif // USE_ENERGY_MARGIN_DETECTION #endif // USE_ENERGY_MARGIN_DETECTION
case FUNC_SERIAL: case FUNC_SERIAL:

View File

@ -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). // 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 // 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 // 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[] = { const uint8_t _ledTable[] = {
#endif
// 11 bits resolution // 11 bits resolution
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, // 11 bits, 0..2047 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 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 // bits_resolution: the resolution of _ledTable[v], between 8 and 11
uint32_t bits_resolution = 11 - (v / 64); // 8..11 uint32_t bits_resolution = 11 - (v / 64); // 8..11
int32_t bits_correction = bits_out - bits_resolution; // -3..3 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 uint32_t uncorrected_value = _ledTable[v]; // 0..255
#endif
if (0 == bits_correction) { if (0 == bits_correction) {
// we already match the required resolution, no change // we already match the required resolution, no change
result = uncorrected_value; result = uncorrected_value;

View File

@ -109,7 +109,6 @@ struct M_FILT {
float rbuff[1]; float rbuff[1];
}; };
typedef union { typedef union {
uint8_t data; uint8_t data;
struct { struct {
@ -200,8 +199,6 @@ void RulesTeleperiod(void) {
if (bitRead(Settings.rule_enabled, 0) && mqtt_data[0]) Run_Scripter(">T",2, mqtt_data); if (bitRead(Settings.rule_enabled, 0) && mqtt_data[0]) Run_Scripter(">T",2, mqtt_data);
} }
//#define USE_24C256
// EEPROM MACROS // EEPROM MACROS
#ifdef USE_24C256 #ifdef USE_24C256
#ifndef USE_SCRIPT_FATFS #ifndef USE_SCRIPT_FATFS
@ -710,6 +707,91 @@ float DoMedian5(uint8_t index, float in) {
return median_array(mf->buffer,MEDIAN_SIZE); 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 // vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
// no flash strings here for performance reasons!!! // no flash strings here for performance reasons!!!
@ -1212,6 +1294,30 @@ chknext:
} }
goto strexit; 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; break;
case 'i': case 'i':
if (!strncmp(vname,"int(",4)) { if (!strncmp(vname,"int(",4)) {
@ -2046,6 +2152,9 @@ exit:
#define IF_NEST 8 #define IF_NEST 8
// execute section of scripter // execute section of scripter
int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { 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; uint8_t vtype=0,sindex,xflg,floop=0,globvindex;
int8_t globaindex; int8_t globaindex;
struct T_INDEX ind; struct T_INDEX ind;
@ -2060,9 +2169,6 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
check=1; check=1;
} }
if (tasm_cmd_activ) return 0;
float *dfvar,*cv_count,cv_max,cv_inc; float *dfvar,*cv_count,cv_max,cv_inc;
char *cv_ptr; char *cv_ptr;
float fvar=0,fvar1,sysvar,swvar; float fvar=0,fvar1,sysvar,swvar;
@ -3224,10 +3330,11 @@ bool ScriptMqttData(void)
} }
} }
value.trim(); value.trim();
//Create an new event. Cannot directly call RulesProcessEvent(). //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()); //snprintf_P(event_data, sizeof(event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str());
char sbuffer[128]; 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); //toLog(sbuffer);
execute_script(sbuffer); execute_script(sbuffer);
} }

View File

@ -129,6 +129,7 @@ const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM =
const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM =
",\"uniq_id\":\"%s\"," ",\"uniq_id\":\"%s\","
"\"device\":{\"identifiers\":[\"%06X\"]," "\"device\":{\"identifiers\":[\"%06X\"],"
"\"connections\":[[\"mac\",\"%s\"]],"
"\"name\":\"%s\"," "\"name\":\"%s\","
"\"model\":\"%s\"," "\"model\":\"%s\","
"\"sw_version\":\"%s%s\"," "\"sw_version\":\"%s%s\","
@ -136,7 +137,8 @@ const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM =
const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM =
",\"uniq_id\":\"%s\"," ",\"uniq_id\":\"%s\","
"\"device\":{\"identifiers\":[\"%06X\"]}"; "\"device\":{\"identifiers\":[\"%06X\"],"
"\"connections\":[[\"mac\",\"%s\"]]}";
const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM = const char HASS_DISCOVER_TOPIC_PREFIX[] PROGMEM =
",\"~\":\"%s\""; ",\"~\":\"%s\"";
@ -237,7 +239,7 @@ void HAssAnnounceRelayLight(void)
Shorten(&availability_topic, prefix); 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); 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); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (is_light) { if (is_light) {
@ -317,7 +319,7 @@ void HAssAnnounceButtonSwitch(uint8_t device, char* topic, uint8_t present, uint
Shorten(&state_topic, prefix); Shorten(&state_topic, prefix);
Shorten(&availability_topic, prefix); Shorten(&availability_topic, prefix);
Response_P(HASS_DISCOVER_BUTTON_SWITCH, name, state_topic, Settings.state_text[toggle?2:1], availability_topic); 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 (strlen(prefix) > 0 ) TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (toggle) TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_TOGGLE); if (toggle) TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_TOGGLE);
else TryResponseAppend_P(HASS_DISCOVER_BUTTON_SWITCH_ONOFF, Settings.state_text[0]); 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); Shorten(&availability_topic, prefix);
Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic); 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); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) { if (!strcmp_P(subsensortype, PSTR(D_JSON_TEMPERATURE))) {
TryResponseAppend_P(HASS_DISCOVER_SENSOR_TEMP, TempUnit(), sensorname); 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); Response_P(HASS_DISCOVER_SENSOR, name, state_topic, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_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); Settings.friendlyname[0], ModuleName().c_str(), my_version, my_image);
TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix); TryResponseAppend_P(HASS_DISCOVER_TOPIC_PREFIX, prefix);
TryResponseAppend_P(PSTR("}")); TryResponseAppend_P(PSTR("}"));

View File

@ -41,33 +41,35 @@
#define HLW_SAMPLE_COUNT 10 // Max number of samples per cycle #define HLW_SAMPLE_COUNT 10 // Max number of samples per cycle
//#define HLW_DEBUG //#define HLW_DEBUG
struct HLW {
#ifdef HLW_DEBUG #ifdef HLW_DEBUG
unsigned long hlw_debug[HLW_SAMPLE_COUNT]; unsigned long debug[HLW_SAMPLE_COUNT];
#endif #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 cf1_pulse_length = 0;
unsigned long hlw_cf_pulse_last_time = 0; unsigned long cf1_pulse_last_time = 0;
unsigned long hlw_cf_power_pulse_length = 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 energy_period_counter = 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 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; uint8_t model_type = 0;
unsigned long hlw_voltage_ratio = 0; uint8_t cf1_timer = 0;
unsigned long hlw_current_ratio = 0; uint8_t power_retry = 0;
bool select_ui_flag = false;
uint8_t hlw_select_ui_flag = 0; bool ui_flag = true;
uint8_t hlw_ui_flag = 1; bool load_off = true;
uint8_t hlw_model_type = 0; } Hlw;
uint8_t hlw_load_off = 1;
uint8_t hlw_cf1_timer = 0;
uint8_t hlw_power_retry = 0;
// Fix core 2.5.x ISR not in IRAM Exception // Fix core 2.5.x ISR not in IRAM Exception
#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception #ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception
@ -79,34 +81,34 @@ void HlwCfInterrupt(void) // Service Power
{ {
unsigned long us = micros(); unsigned long us = micros();
if (hlw_load_off) { // Restart plen measurement if (Hlw.load_off) { // Restart plen measurement
hlw_cf_pulse_last_time = us; Hlw.cf_pulse_last_time = us;
hlw_load_off = 0; Hlw.load_off = false;
} else { } else {
hlw_cf_pulse_length = us - hlw_cf_pulse_last_time; Hlw.cf_pulse_length = us - Hlw.cf_pulse_last_time;
hlw_cf_pulse_last_time = us; Hlw.cf_pulse_last_time = us;
hlw_energy_period_counter++; Hlw.energy_period_counter++;
} }
energy_data_valid = 0; Energy.data_valid = 0;
} }
void HlwCf1Interrupt(void) // Service Voltage and Current void HlwCf1Interrupt(void) // Service Voltage and Current
{ {
unsigned long us = micros(); unsigned long us = micros();
hlw_cf1_pulse_length = us - hlw_cf1_pulse_last_time; Hlw.cf1_pulse_length = us - Hlw.cf1_pulse_last_time;
hlw_cf1_pulse_last_time = us; 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 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_summed_pulse_length += Hlw.cf1_pulse_length;
#ifdef HLW_DEBUG #ifdef HLW_DEBUG
hlw_debug[hlw_cf1_pulse_counter] = hlw_cf1_pulse_length; Hlw.debug[Hlw.cf1_pulse_counter] = Hlw.cf1_pulse_length;
#endif #endif
hlw_cf1_pulse_counter++; Hlw.cf1_pulse_counter++;
if (HLW_SAMPLE_COUNT == 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_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_u = 0;
unsigned long hlw_i = 0; unsigned long hlw_i = 0;
if (micros() - hlw_cf_pulse_last_time > (HLW_POWER_PROBE_TIME * 1000000)) { if (micros() - Hlw.cf_pulse_last_time > (HLW_POWER_PROBE_TIME * 1000000)) {
hlw_cf_pulse_length = 0; // No load for some time Hlw.cf_pulse_length = 0; // No load for some time
hlw_load_off = 1; 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) { 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 hlw_w = (Hlw.power_ratio * Settings.energy_power_calibration) / Hlw.cf_power_pulse_length ; // W *10
energy_active_power = (float)hlw_w / 10; Energy.active_power = (float)hlw_w / 10;
hlw_power_retry = 1; // Workaround issue #5161 Hlw.power_retry = 1; // Workaround issue #5161
} else { } else {
if (hlw_power_retry) { if (Hlw.power_retry) {
hlw_power_retry--; Hlw.power_retry--;
} else { } else {
energy_active_power = 0; Energy.active_power = 0;
} }
} }
if (pin[GPIO_NRG_CF1] < 99) { if (pin[GPIO_NRG_CF1] < 99) {
hlw_cf1_timer++; Hlw.cf1_timer++;
if (hlw_cf1_timer >= 8) { if (Hlw.cf1_timer >= 8) {
hlw_cf1_timer = 0; Hlw.cf1_timer = 0;
hlw_select_ui_flag = (hlw_select_ui_flag) ? 0 : 1; Hlw.select_ui_flag = (Hlw.select_ui_flag) ? false : true;
if (pin[GPIO_NRG_SEL] < 99) { 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) { if (Hlw.cf1_pulse_counter) {
cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter; cf1_pulse_length = Hlw.cf1_summed_pulse_length / Hlw.cf1_pulse_counter;
} }
#ifdef HLW_DEBUG #ifdef HLW_DEBUG
// Debugging for calculating mean and median // Debugging for calculating mean and median
char stemp[100]; char stemp[100];
stemp[0] = '\0'; stemp[0] = '\0';
for (uint32_t i = 0; i < hlw_cf1_pulse_counter; i++) { for (uint32_t i = 0; i < Hlw.cf1_pulse_counter; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("%s %d"), stemp, hlw_debug[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 i = 0; i < Hlw.cf1_pulse_counter; i++) {
for (uint32_t j = i + 1; j < hlw_cf1_pulse_counter; j++) { for (uint32_t j = i + 1; j < Hlw.cf1_pulse_counter; j++) {
if (hlw_debug[i] > hlw_debug[j]) { // Sort ascending if (Hlw.debug[i] > Hlw.debug[j]) { // Sort ascending
std::swap(hlw_debug[i], hlw_debug[j]); 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"), 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 #endif
if (hlw_select_ui_flag == hlw_ui_flag) { if (Hlw.select_ui_flag == Hlw.ui_flag) {
hlw_cf1_voltage_pulse_length = cf1_pulse_length; Hlw.cf1_voltage_pulse_length = cf1_pulse_length;
if (hlw_cf1_voltage_pulse_length && energy_power_on) { // If powered on always provide voltage 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 hlw_u = (Hlw.voltage_ratio * Settings.energy_voltage_calibration) / Hlw.cf1_voltage_pulse_length ; // V *10
energy_voltage = (float)hlw_u / 10; Energy.voltage = (float)hlw_u / 10;
} else { } else {
energy_voltage = 0; Energy.voltage = 0;
} }
} else { } 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 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 hlw_i = (Hlw.current_ratio * Settings.energy_current_calibration) / Hlw.cf1_current_pulse_length; // mA
energy_current = (float)hlw_i / 1000; Energy.current = (float)hlw_i / 1000;
} else { } else {
energy_current = 0; Energy.current = 0;
} }
} }
hlw_cf1_summed_pulse_length = 0; Hlw.cf1_summed_pulse_length = 0;
hlw_cf1_pulse_counter = 0; Hlw.cf1_pulse_counter = 0;
} }
} }
} }
void HlwEverySecond(void) void HlwEverySecond(void)
{ {
if (energy_data_valid > ENERGY_WATCHDOG) { if (Energy.data_valid > ENERGY_WATCHDOG) {
hlw_cf1_voltage_pulse_length = 0; Hlw.cf1_voltage_pulse_length = 0;
hlw_cf1_current_pulse_length = 0; Hlw.cf1_current_pulse_length = 0;
hlw_cf_power_pulse_length = 0; Hlw.cf_power_pulse_length = 0;
} else { } else {
unsigned long hlw_len; unsigned long hlw_len;
if (hlw_energy_period_counter) { if (Hlw.energy_period_counter) {
hlw_len = 10000 / hlw_energy_period_counter; hlw_len = 10000 / Hlw.energy_period_counter;
hlw_energy_period_counter = 0; Hlw.energy_period_counter = 0;
if (hlw_len) { 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(); EnergyUpdateToday();
} }
} }
@ -223,19 +225,19 @@ void HlwSnsInit(void)
Settings.energy_current_calibration = HLW_IREF_PULSE; Settings.energy_current_calibration = HLW_IREF_PULSE;
} }
if (hlw_model_type) { if (Hlw.model_type) {
hlw_power_ratio = HJL_PREF; Hlw.power_ratio = HJL_PREF;
hlw_voltage_ratio = HJL_UREF; Hlw.voltage_ratio = HJL_UREF;
hlw_current_ratio = HJL_IREF; Hlw.current_ratio = HJL_IREF;
} else { } else {
hlw_power_ratio = HLW_PREF; Hlw.power_ratio = HLW_PREF;
hlw_voltage_ratio = HLW_UREF; Hlw.voltage_ratio = HLW_UREF;
hlw_current_ratio = HLW_IREF; Hlw.current_ratio = HLW_IREF;
} }
if (pin[GPIO_NRG_SEL] < 99) { if (pin[GPIO_NRG_SEL] < 99) {
pinMode(pin[GPIO_NRG_SEL], OUTPUT); 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) { if (pin[GPIO_NRG_CF1] < 99) {
pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP); pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP);
@ -248,29 +250,29 @@ void HlwSnsInit(void)
void HlwDrvInit(void) void HlwDrvInit(void)
{ {
if (!energy_flg) { if (!energy_flg) {
hlw_model_type = 0; // HLW8012 Hlw.model_type = 0; // HLW8012
if (pin[GPIO_HJL_CF] < 99) { if (pin[GPIO_HJL_CF] < 99) {
pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF];
pin[GPIO_HJL_CF] = 99; 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 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) { if (pin[GPIO_NRG_SEL_INV] < 99) {
pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV];
pin[GPIO_NRG_SEL_INV] = 99; 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 (pin[GPIO_NRG_CF1] < 99) { // Voltage and/or Current monitor
if (99 == pin[GPIO_NRG_SEL]) { // Voltage and/or Current selector if (99 == pin[GPIO_NRG_SEL]) { // Voltage and/or Current selector
energy_current_available = false; // Assume Voltage Energy.current_available = false; // Assume Voltage
} }
} else { } else {
energy_current_available = false; Energy.current_available = false;
energy_voltage_available = false; Energy.voltage_available = false;
} }
energy_flg = XNRG_01; energy_flg = XNRG_01;
@ -282,22 +284,22 @@ bool HlwCommand(void)
{ {
bool serviced = true; 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 // Service in xdrv_03_energy.ino
} }
else if (CMND_POWERSET == energy_command_code) { else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && hlw_cf_power_pulse_length) { 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; 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) { else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && hlw_cf1_voltage_pulse_length) { 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; 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) { else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && hlw_cf1_current_pulse_length) { 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; Settings.energy_current_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio;
} }
} }
else serviced = false; // Unknown command else serviced = false; // Unknown command

View File

@ -37,15 +37,17 @@
#define CSE_PREF 1000 #define CSE_PREF 1000
#define CSE_UREF 100 #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; uint8_t power_invalid = 0;
long current_cycle = 0; bool received = false;
long power_cycle = 0; } Cse;
long power_cycle_first = 0;
long cf_pulses = 0;
long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
uint8_t cse_power_invalid = 0;
void CseReceived(void) void CseReceived(void)
{ {
@ -84,54 +86,54 @@ void CseReceived(void)
} }
uint8_t adjustement = serial_in_buffer[20]; uint8_t adjustement = serial_in_buffer[20];
voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7]; Cse.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]; Cse.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]; Cse.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.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 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 if (adjustement & 0x10) { // Power valid
cse_power_invalid = 0; Cse.power_invalid = 0;
if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range
energy_active_power = 0; Energy.active_power = 0;
} else { } else {
if (0 == power_cycle_first) { power_cycle_first = power_cycle; } // Skip first incomplete power_cycle if (0 == Cse.power_cycle_first) { Cse.power_cycle_first = Cse.power_cycle; } // Skip first incomplete Cse.power_cycle
if (power_cycle_first != power_cycle) { if (Cse.power_cycle_first != Cse.power_cycle) {
power_cycle_first = -1; Cse.power_cycle_first = -1;
energy_active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle; Energy.active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle;
} else { } else {
energy_active_power = 0; Energy.active_power = 0;
} }
} }
} else { } else {
if (cse_power_invalid < Settings.param[P_CSE7766_INVALID_POWER]) { // Allow measurements down to about 1W if (Cse.power_invalid < Settings.param[P_CSE7766_INVALID_POWER]) { // Allow measurements down to about 1W
cse_power_invalid++; Cse.power_invalid++;
} else { } else {
power_cycle_first = 0; Cse.power_cycle_first = 0;
energy_active_power = 0; // Powered on but no load Energy.active_power = 0; // Powered on but no load
} }
} }
if (adjustement & 0x20) { // Current valid if (adjustement & 0x20) { // Current valid
if (0 == energy_active_power) { if (0 == Energy.active_power) {
energy_current = 0; Energy.current = 0;
} else { } 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 } else { // Powered off
power_cycle_first = 0; Cse.power_cycle_first = 0;
energy_voltage = 0; Energy.voltage = 0;
energy_active_power = 0; Energy.active_power = 0;
energy_current = 0; Energy.current = 0;
} }
} }
bool CseSerialInput(void) bool CseSerialInput(void)
{ {
if (cse_receive_flag) { if (Cse.received) {
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if (24 == serial_in_byte_counter) { if (24 == serial_in_byte_counter) {
@ -140,9 +142,9 @@ bool CseSerialInput(void)
uint8_t checksum = 0; uint8_t checksum = 0;
for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; } for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; }
if (checksum == serial_in_buffer[23]) { if (checksum == serial_in_buffer[23]) {
energy_data_valid = 0; Energy.data_valid = 0;
CseReceived(); CseReceived();
cse_receive_flag = 0; Cse.received = false;
return 1; return 1;
} else { } else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE)); AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
@ -151,14 +153,14 @@ bool CseSerialInput(void)
serial_in_byte_counter--; serial_in_byte_counter--;
} while ((serial_in_byte_counter > 2) && (0x5A != serial_in_buffer[1])); } while ((serial_in_byte_counter > 2) && (0x5A != serial_in_buffer[1]));
if (0x5A != serial_in_buffer[1]) { if (0x5A != serial_in_buffer[1]) {
cse_receive_flag = 0; Cse.received = false;
serial_in_byte_counter = 0; serial_in_byte_counter = 0;
} }
} }
} }
} else { } else {
if ((0x5A == serial_in_byte) && (1 == serial_in_byte_counter)) { // 0x5A - Packet header 2 if ((0x5A == serial_in_byte) && (1 == serial_in_byte_counter)) { // 0x5A - Packet header 2
cse_receive_flag = 1; Cse.received = true;
} else { } else {
serial_in_byte_counter = 0; serial_in_byte_counter = 0;
} }
@ -172,31 +174,31 @@ bool CseSerialInput(void)
void CseEverySecond(void) void CseEverySecond(void)
{ {
if (energy_data_valid > ENERGY_WATCHDOG) { if (Energy.data_valid > ENERGY_WATCHDOG) {
voltage_cycle = 0; Cse.voltage_cycle = 0;
current_cycle = 0; Cse.current_cycle = 0;
power_cycle = 0; Cse.power_cycle = 0;
} else { } else {
long cf_frequency = 0; long cf_frequency = 0;
if (CSE_PULSES_NOT_INITIALIZED == cf_pulses_last_time) { if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) {
cf_pulses_last_time = cf_pulses; // Init after restart Cse.cf_pulses_last_time = Cse.cf_pulses; // Init after restart
} else { } else {
if (cf_pulses < cf_pulses_last_time) { // Rolled over after 65535 pulses if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 65535 pulses
cf_frequency = (65536 - cf_pulses_last_time) + cf_pulses; cf_frequency = (65536 - Cse.cf_pulses_last_time) + Cse.cf_pulses;
} else { } 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; unsigned long delta = (cf_frequency * Settings.energy_power_calibration) / 36;
// prevent invalid load delta steps even checksum is valid (issue #5789): // 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 if (delta <= (3680*100/36) * 10 ) { // max load for S31/Pow R2: 3.68kW
cf_pulses_last_time = cf_pulses; Cse.cf_pulses_last_time = Cse.cf_pulses;
energy_kWhtoday_delta += delta; Energy.kWhtoday_delta += delta;
} }
else { else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow")); 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(); EnergyUpdateToday();
} }
@ -213,7 +215,7 @@ void CseDrvInit(void)
if (0 == Settings.param[P_CSE7766_INVALID_POWER]) { if (0 == Settings.param[P_CSE7766_INVALID_POWER]) {
Settings.param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 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; energy_flg = XNRG_02;
} }
} }
@ -223,19 +225,19 @@ bool CseCommand(void)
{ {
bool serviced = true; bool serviced = true;
if (CMND_POWERSET == energy_command_code) { if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && power_cycle) { if (XdrvMailbox.data_len && Cse.power_cycle) {
Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * power_cycle) / CSE_PREF; Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF;
} }
} }
else if (CMND_VOLTAGESET == energy_command_code) { else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && voltage_cycle) { if (XdrvMailbox.data_len && Cse.voltage_cycle) {
Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF;
} }
} }
else if (CMND_CURRENTSET == energy_command_code) { else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && current_cycle) { if (XdrvMailbox.data_len && Cse.current_cycle) {
Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * current_cycle) / 1000; Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000;
} }
} }
else serviced = false; // Unknown command else serviced = false; // Unknown command

View File

@ -169,22 +169,22 @@ void PzemEvery200ms(void)
if (data_ready) { if (data_ready) {
float value = 0; float value = 0;
if (PzemRecieve(pzem_responses[pzem_read_state], &value)) { if (PzemRecieve(pzem_responses[pzem_read_state], &value)) {
energy_data_valid = 0; Energy.data_valid = 0;
switch (pzem_read_state) { switch (pzem_read_state) {
case 1: // Voltage as 230.2V case 1: // Voltage as 230.2V
energy_voltage = value; Energy.voltage = value;
break; break;
case 2: // Current as 17.32A case 2: // Current as 17.32A
energy_current = value; Energy.current = value;
break; break;
case 3: // Power as 20W case 3: // Power as 20W
energy_active_power = value; Energy.active_power = value;
break; break;
case 4: // Total energy as 99999Wh 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 (!Energy.start_energy || (value < Energy.start_energy)) Energy.start_energy = value; // Init after restart and hanlde roll-over if any
if (value != energy_start) { if (value != Energy.start_energy) {
energy_kWhtoday += (unsigned long)((value - energy_start) * 100); Energy.kWhtoday += (unsigned long)((value - Energy.start_energy) * 100);
energy_start = value; Energy.start_energy = value;
} }
EnergyUpdateToday(); EnergyUpdateToday();
break; break;

View File

@ -454,22 +454,22 @@ void McpParseData(void)
// mcp_power_factor = McpExtractInt(mcp_buffer, 20, 2); // mcp_power_factor = McpExtractInt(mcp_buffer, 20, 2);
mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2); mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2);
if (energy_power_on) { // Powered on if (Energy.power_on) { // Powered on
energy_frequency = (float)mcp_line_frequency / 1000; Energy.frequency = (float)mcp_line_frequency / 1000;
energy_voltage = (float)mcp_voltage_rms / 10; Energy.voltage = (float)mcp_voltage_rms / 10;
energy_active_power = (float)mcp_active_power / 100; Energy.active_power = (float)mcp_active_power / 100;
if (0 == energy_active_power) { if (0 == Energy.active_power) {
energy_current = 0; Energy.current = 0;
} else { } else {
energy_current = (float)mcp_current_rms / 10000; Energy.current = (float)mcp_current_rms / 10000;
} }
} else { // Powered off } else { // Powered off
energy_frequency = 0; Energy.frequency = 0;
energy_voltage = 0; Energy.voltage = 0;
energy_active_power = 0; Energy.active_power = 0;
energy_current = 0; Energy.current = 0;
} }
energy_data_valid = 0; Energy.data_valid = 0;
} }
/********************************************************************************************/ /********************************************************************************************/
@ -527,7 +527,7 @@ void McpSerialInput(void)
void McpEverySecond(void) void McpEverySecond(void)
{ {
if (energy_data_valid > ENERGY_WATCHDOG) { if (Energy.data_valid > ENERGY_WATCHDOG) {
mcp_voltage_rms = 0; mcp_voltage_rms = 0;
mcp_current_rms = 0; mcp_current_rms = 0;
mcp_active_power = 0; mcp_active_power = 0;
@ -535,7 +535,7 @@ void McpEverySecond(void)
} }
if (mcp_active_power) { if (mcp_active_power) {
energy_kWhtoday_delta += ((mcp_active_power * 10) / 36); Energy.kWhtoday_delta += ((mcp_active_power * 10) / 36);
EnergyUpdateToday(); EnergyUpdateToday();
} }
@ -602,7 +602,7 @@ bool McpCommand(void)
bool serviced = true; bool serviced = true;
unsigned long value = 0; unsigned long value = 0;
if (CMND_POWERSET == energy_command_code) { if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && mcp_active_power) { if (XdrvMailbox.data_len && mcp_active_power) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100); value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100);
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W 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) { if (XdrvMailbox.data_len && mcp_voltage_rms) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 1000) && (value < 2600)) { // Between 100V and 260V 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) { if (XdrvMailbox.data_len && mcp_current_rms) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 100) && (value < 80000)) { // Between 10mA and 8A 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) { if (XdrvMailbox.data_len && mcp_line_frequency) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000); value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000);
if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz

View File

@ -70,22 +70,22 @@ void PzemAcEverySecond(void)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error); AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error);
} else { } else {
// if ((PzemCalculateCRC(buffer, 23)) == ((buffer[24] << 8) | buffer[23])) { // 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 // 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 // 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-- // 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.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.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.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.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.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 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.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != energy_start) { if (energy != Energy.start_energy) {
energy_kWhtoday += (unsigned long)((energy - energy_start) * 100); Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
energy_start = energy; Energy.start_energy = energy;
} }
EnergyUpdateToday(); EnergyUpdateToday();
// } // }

View File

@ -51,20 +51,20 @@ void PzemDcEverySecond(void)
if (error) { if (error) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error); AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error);
} else { } 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 // 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 // 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-- // Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc--
energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V 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.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.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 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.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != energy_start) { if (energy != Energy.start_energy) {
energy_kWhtoday += (unsigned long)((energy - energy_start) * 100); Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
energy_start = energy; Energy.start_energy = energy;
} }
EnergyUpdateToday(); EnergyUpdateToday();
} }
@ -85,7 +85,7 @@ void PzemDcSnsInit(void)
uint8_t result = PzemDcModbus->Begin(9600, 2); // Uses two stop bits!! uint8_t result = PzemDcModbus->Begin(9600, 2); // Uses two stop bits!!
if (result) { if (result) {
if (2 == result) { ClaimSerial(); } if (2 == result) { ClaimSerial(); }
energy_type_dc = true; Energy.type_dc = true;
} else { } else {
energy_flg = ENERGY_NONE; energy_flg = ENERGY_NONE;
} }

View File

@ -36,14 +36,16 @@
#define ADE7953_ADDR 0x38 #define ADE7953_ADDR 0x38
uint32_t ade7953_active_power = 0; struct Ade7953 {
uint32_t ade7953_active_power1 = 0; uint32_t active_power = 0;
uint32_t ade7953_active_power2 = 0; uint32_t active_power1 = 0;
uint32_t ade7953_current_rms = 0; uint32_t active_power2 = 0;
uint32_t ade7953_current_rms1 = 0; uint32_t current_rms = 0;
uint32_t ade7953_current_rms2 = 0; uint32_t current_rms1 = 0;
uint32_t ade7953_voltage_rms = 0; uint32_t current_rms2 = 0;
uint8_t ade7953_init = 0; uint32_t voltage_rms = 0;
uint8_t init_step = 0;
} Ade7953;
int Ade7953RegSize(uint16_t reg) int Ade7953RegSize(uint16_t reg)
{ {
@ -109,57 +111,57 @@ void Ade7953GetData(void)
{ {
int32_t active_power; int32_t active_power;
ade7953_voltage_rms = Ade7953Read(0x31C); // Both relays Ade7953.voltage_rms = Ade7953Read(0x31C); // Both relays
ade7953_current_rms1 = Ade7953Read(0x31B); // Relay 1 Ade7953.current_rms1 = Ade7953Read(0x31B); // Relay 1
if (ade7953_current_rms1 < 2000) { // No load threshold (20mA) if (Ade7953.current_rms1 < 2000) { // No load threshold (20mA)
ade7953_current_rms1 = 0; Ade7953.current_rms1 = 0;
ade7953_active_power1 = 0; Ade7953.active_power1 = 0;
} else { } else {
active_power = (int32_t)Ade7953Read(0x313) * -1; // Relay 1 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 Ade7953.current_rms2 = Ade7953Read(0x31A); // Relay 2
if (ade7953_current_rms2 < 2000) { // No load threshold (20mA) if (Ade7953.current_rms2 < 2000) { // No load threshold (20mA)
ade7953_current_rms2 = 0; Ade7953.current_rms2 = 0;
ade7953_active_power2 = 0; Ade7953.active_power2 = 0;
} else { } else {
active_power = (int32_t)Ade7953Read(0x312); // Relay 2 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 // First phase only supports accumulated Current and Power
ade7953_current_rms = ade7953_current_rms1 + ade7953_current_rms2; Ade7953.current_rms = Ade7953.current_rms1 + Ade7953.current_rms2;
ade7953_active_power = ade7953_active_power1 + ade7953_active_power2; 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"), 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 if (Energy.power_on) { // Powered on
energy_voltage = (float)ade7953_voltage_rms / Settings.energy_voltage_calibration; Energy.voltage = (float)Ade7953.voltage_rms / Settings.energy_voltage_calibration;
energy_active_power = (float)ade7953_active_power / (Settings.energy_power_calibration / 10); Energy.active_power = (float)Ade7953.active_power / (Settings.energy_power_calibration / 10);
if (0 == energy_active_power) { if (0 == Energy.active_power) {
energy_current = 0; Energy.current = 0;
} else { } 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 } else { // Powered off
energy_voltage = 0; Energy.voltage = 0;
energy_active_power = 0; Energy.active_power = 0;
energy_current = 0; Energy.current = 0;
} }
if (ade7953_active_power) { if (Ade7953.active_power) {
energy_kWhtoday_delta += ((ade7953_active_power * (100000 / (Settings.energy_power_calibration / 10))) / 3600); Energy.kWhtoday_delta += ((Ade7953.active_power * (100000 / (Settings.energy_power_calibration / 10))) / 3600);
EnergyUpdateToday(); EnergyUpdateToday();
} }
} }
void Ade7953EnergyEverySecond() void Ade7953EnergyEverySecond()
{ {
if (ade7953_init) { if (Ade7953.init_step) {
if (1 == ade7953_init) { if (1 == Ade7953.init_step) {
Ade7953Init(); Ade7953Init();
} }
ade7953_init--; Ade7953.init_step--;
} else { } else {
Ade7953GetData(); Ade7953GetData();
} }
@ -177,7 +179,7 @@ void Ade7953DrvInit(void)
Settings.energy_current_calibration = ADE7953_IREF; Settings.energy_current_calibration = ADE7953_IREF;
} }
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADE7953", ADE7953_ADDR); AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "ADE7953", ADE7953_ADDR);
ade7953_init = 2; Ade7953.init_step = 2;
energy_flg = XNRG_07; energy_flg = XNRG_07;
} }
} }
@ -190,36 +192,36 @@ bool Ade7953Command(void)
uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 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; } if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; }
// Service in xdrv_03_energy.ino // 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; } if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_UREF; }
// Service in xdrv_03_energy.ino // 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; } if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_IREF; }
// Service in xdrv_03_energy.ino // Service in xdrv_03_energy.ino
} }
else if (CMND_POWERSET == energy_command_code) { else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && ade7953_active_power) { if (XdrvMailbox.data_len && Ade7953.active_power) {
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W 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) { else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && ade7953_voltage_rms) { if (XdrvMailbox.data_len && Ade7953.voltage_rms) {
if ((value > 10000) && (value < 26000)) { // Between 100V and 260V 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) { else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && ade7953_current_rms) { if (XdrvMailbox.data_len && Ade7953.current_rms) {
if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A 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
} }
} }
} }

View File

@ -422,6 +422,428 @@ 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 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;
}
char* XsnsSensorsAvailable(char* sensors)
{
// 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
snprintf_P(sensors, LOGSZ, PSTR("%s%s%d"), sensors, (!i) ? "[" : ",", sensorid);
}
snprintf_P(sensors, LOGSZ, PSTR("%s]"), sensors); // Max length is about 3 x 96 < LOGSZ
return sensors;
}
/*********************************************************************************************\ /*********************************************************************************************\
* Function call to all xsns * Function call to all xsns
\*********************************************************************************************/ \*********************************************************************************************/
@ -453,6 +875,8 @@ bool XsnsCall(uint8_t Function)
if (XsnsEnabled(x)) { if (XsnsEnabled(x)) {
#endif #endif
if ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(x)) { continue; } // Skip web info for disabled sensors
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND #ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
uint32_t profile_start_millis = millis(); uint32_t profile_start_millis = millis();
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND #endif // PROFILE_XSNS_SENSOR_EVERY_SECOND

View File

@ -24,256 +24,6 @@
* Needs to be the last alphabetical file due to DEFINE compile order * 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) bool XsnsPresent(uint8_t sns_index)
{ {
uint8_t index = 0; uint8_t index = 0;