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
>**\>B**
executed on BOOT time
executed on BOOT time and script save
>**\>T**
executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section
@ -183,6 +183,7 @@ and on the same line conditions may be bracketed e.g. if ((a==b) and ((c==d) or
**spin(x m)** set gpio pin x (0-16) to value m (0,1) only the last bit is used, so even values set the pin to zero and uneven values set the pin to 1
**spinm(x m)** set pin mode gpio pin x (0-16) to mode m (input=0,output=1,input with pullup=2)
**ws2812(array)** copies an array (defined with m:name) to the WS2812 LED chain the array should be defined as long as the number of pixels. the color is coded as 24 bit RGB
**hsvrgb(h s v)** converts hue (0-360), saturation (0-100) and value (0-100) to RGB color
>**#name** names a subroutine, subroutines are called with **=#name**
**#name(param)** names a subroutines with a parameter is called with **=#name(param)**

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
* 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.

View File

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

View File

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

View File

@ -24,7 +24,7 @@
* Performance ROM (PROGMEM) vs RAM (RODATA)
\*********************************************************************************************/
//#define XFUNC_PTR_IN_ROM // Enable for keeping tables in ROM (PROGMEM) which seem to have access issues on some flash types
#define XFUNC_PTR_IN_ROM // Enable for keeping tables in ROM (PROGMEM) which seem to have access issues on some flash types
/*********************************************************************************************\
* Default sensor states

View File

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

View File

@ -331,12 +331,13 @@ void CmndStatus(void)
}
if ((0 == payload) || (4 == payload)) {
char sensors[LOGSZ];
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\""
D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\""
D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]}}"),
D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"],\"Sensors\":%s}}"),
ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024,
ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipId(), ESP.getFlashChipMode(),
LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5);
LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, XsnsSensorsAvailable(sensors));
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;
} Web;
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg(const char* arg, char* out, size_t max)
{
@ -2461,13 +2460,13 @@ const char kWebCommands[] PROGMEM = "|" // No prefix
#ifdef USE_EMULATION
D_CMND_EMULATION "|"
#endif
D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR ;
D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_WEBSENSOR;
void (* const WebCommand[])(void) PROGMEM = {
#ifdef USE_EMULATION
&CmndEmulation,
#endif
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor };
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor };
/*********************************************************************************************\
* Commands
@ -2564,6 +2563,16 @@ void CmndWebColor(void)
ResponseAppend_P(PSTR("]}"));
}
void CmndWebSensor(void)
{
if (XdrvMailbox.index < MAX_XSNS_DRIVERS) {
if (XdrvMailbox.payload >= 0) {
bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1);
}
ResponseCmndIdxChar(GetStateText(bitRead(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32)));
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/

View File

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

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).
// We're using the fact that lower values are small and can fit within 8 bits
// To save flash space, the array is only 8 bits uint
#ifdef XFUNC_PTR_IN_ROM
const uint8_t _ledTable[] PROGMEM = {
#else
const uint8_t _ledTable[] = {
#endif
// 11 bits resolution
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, // 11 bits, 0..2047
2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, // 11 bits, 0..2047
@ -997,7 +1001,11 @@ uint16_t ledGamma(uint8_t v, uint16_t bits_out = 8) {
// bits_resolution: the resolution of _ledTable[v], between 8 and 11
uint32_t bits_resolution = 11 - (v / 64); // 8..11
int32_t bits_correction = bits_out - bits_resolution; // -3..3
#ifdef XFUNC_PTR_IN_ROM
uint32_t uncorrected_value = pgm_read_byte(_ledTable + v); // 0..255
#else
uint32_t uncorrected_value = _ledTable[v]; // 0..255
#endif
if (0 == bits_correction) {
// we already match the required resolution, no change
result = uncorrected_value;

View File

@ -109,7 +109,6 @@ struct M_FILT {
float rbuff[1];
};
typedef union {
uint8_t data;
struct {
@ -200,8 +199,6 @@ void RulesTeleperiod(void) {
if (bitRead(Settings.rule_enabled, 0) && mqtt_data[0]) Run_Scripter(">T",2, mqtt_data);
}
//#define USE_24C256
// EEPROM MACROS
#ifdef USE_24C256
#ifndef USE_SCRIPT_FATFS
@ -710,6 +707,91 @@ float DoMedian5(uint8_t index, float in) {
return median_array(mf->buffer,MEDIAN_SIZE);
}
#ifdef USE_LIGHT
#ifdef USE_WS2812
uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) {
float r = 0, g = 0, b = 0;
struct HSV {
float H;
float S;
float V;
} hsv;
hsv.H=hue;
hsv.S=(float)saturation/100.0;
hsv.V=(float)value/100.0;
if (hsv.S == 0) {
r = hsv.V;
g = hsv.V;
b = hsv.V;
} else {
int i;
float f, p, q, t;
if (hsv.H == 360)
hsv.H = 0;
else
hsv.H = hsv.H / 60;
i = (int)trunc(hsv.H);
f = hsv.H - i;
p = hsv.V * (1.0 - hsv.S);
q = hsv.V * (1.0 - (hsv.S * f));
t = hsv.V * (1.0 - (hsv.S * (1.0 - f)));
switch (i)
{
case 0:
r = hsv.V;
g = t;
b = p;
break;
case 1:
r = q;
g = hsv.V;
b = p;
break;
case 2:
r = p;
g = hsv.V;
b = t;
break;
case 3:
r = p;
g = q;
b = hsv.V;
break;
case 4:
r = t;
g = p;
b = hsv.V;
break;
default:
r = hsv.V;
g = p;
b = q;
break;
}
}
uint8_t ir,ig,ib;
ir=r*255;
ig=g*255;
ib=b*255;
uint32_t rgb=(ir<<16)|(ig<<8)|ib;
return rgb;
}
#endif
#endif
// vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
// no flash strings here for performance reasons!!!
@ -1212,6 +1294,30 @@ chknext:
}
goto strexit;
}
#ifdef USE_LIGHT
#ifdef USE_WS2812
if (!strncmp(vname,"hsvrgb(",7)) {
lp=GetNumericResult(lp+7,OPER_EQU,&fvar,0);
if (fvar<0 || fvar>360) fvar=0;
SCRIPT_SKIP_SPACES
// arg2
float fvar2;
lp=GetNumericResult(lp,OPER_EQU,&fvar2,0);
if (fvar2<0 || fvar2>100) fvar2=0;
SCRIPT_SKIP_SPACES
// arg3
float fvar3;
lp=GetNumericResult(lp,OPER_EQU,&fvar3,0);
if (fvar3<0 || fvar3>100) fvar3=0;
fvar=HSVToRGB(fvar,fvar2,fvar3);
lp++;
len=0;
goto exit;
}
#endif
#endif
break;
case 'i':
if (!strncmp(vname,"int(",4)) {
@ -2046,6 +2152,9 @@ exit:
#define IF_NEST 8
// execute section of scripter
int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (tasm_cmd_activ && tlen>0) return 0;
uint8_t vtype=0,sindex,xflg,floop=0,globvindex;
int8_t globaindex;
struct T_INDEX ind;
@ -2060,9 +2169,6 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
check=1;
}
if (tasm_cmd_activ) return 0;
float *dfvar,*cv_count,cv_max,cv_inc;
char *cv_ptr;
float fvar=0,fvar1,sysvar,swvar;
@ -3224,10 +3330,11 @@ bool ScriptMqttData(void)
}
}
value.trim();
//Create an new event. Cannot directly call RulesProcessEvent().
//snprintf_P(event_data, sizeof(event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str());
char sbuffer[128];
snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=%s\n"), event_item.Event.c_str(), value.c_str());
snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=\"%s\"\n"), event_item.Event.c_str(), value.c_str());
//toLog(sbuffer);
execute_script(sbuffer);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -70,22 +70,22 @@ void PzemAcEverySecond(void)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemAc response error %d"), error);
} else {
// if ((PzemCalculateCRC(buffer, 23)) == ((buffer[24] << 8) | buffer[23])) {
energy_data_valid = 0;
Energy.data_valid = 0;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34
// Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc--
energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V
energy_current = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A
energy_active_power = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W
energy_frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz
energy_power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
Energy.voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V
Energy.current = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A
Energy.active_power = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W
Energy.frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz
Energy.power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
float energy = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); // 4294967295 Wh
if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and handle roll-over if any
if (energy != energy_start) {
energy_kWhtoday += (unsigned long)((energy - energy_start) * 100);
energy_start = energy;
if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
Energy.start_energy = energy;
}
EnergyUpdateToday();
// }

View File

@ -51,20 +51,20 @@ void PzemDcEverySecond(void)
if (error) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "PzemDc response error %d"), error);
} else {
energy_data_valid = 0;
Energy.data_valid = 0;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29
// Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc--
energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V
energy_current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A
energy_active_power = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W
Energy.voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V
Energy.current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A
Energy.active_power = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W
float energy = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); // 4294967295 Wh
if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and handle roll-over if any
if (energy != energy_start) {
energy_kWhtoday += (unsigned long)((energy - energy_start) * 100);
energy_start = energy;
if (!Energy.start_energy || (energy < Energy.start_energy)) { Energy.start_energy = energy; } // Init after restart and handle roll-over if any
if (energy != Energy.start_energy) {
Energy.kWhtoday += (unsigned long)((energy - Energy.start_energy) * 100);
Energy.start_energy = energy;
}
EnergyUpdateToday();
}
@ -85,7 +85,7 @@ void PzemDcSnsInit(void)
uint8_t result = PzemDcModbus->Begin(9600, 2); // Uses two stop bits!!
if (result) {
if (2 == result) { ClaimSerial(); }
energy_type_dc = true;
Energy.type_dc = true;
} else {
energy_flg = ENERGY_NONE;
}

View File

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

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
/*********************************************************************************************\
* 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
\*********************************************************************************************/
@ -453,6 +875,8 @@ bool XsnsCall(uint8_t Function)
if (XsnsEnabled(x)) {
#endif
if ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(x)) { continue; } // Skip web info for disabled sensors
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
uint32_t profile_start_millis = millis();
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND

View File

@ -24,256 +24,6 @@
* Needs to be the last alphabetical file due to DEFINE compile order
\*********************************************************************************************/
/*********************************************************************************************\
* Xsns available list
\*********************************************************************************************/
#ifdef XFUNC_PTR_IN_ROM
const uint8_t kXsnsList[] PROGMEM = {
#else
const uint8_t kXsnsList[] = {
#endif
#ifdef XSNS_01
XSNS_01,
#endif
#ifdef XSNS_02
XSNS_02,
#endif
#ifdef XSNS_03
XSNS_03,
#endif
#ifdef XSNS_04
XSNS_04,
#endif
#ifdef XSNS_05
XSNS_05,
#endif
#ifdef XSNS_06
XSNS_06,
#endif
#ifdef XSNS_07
XSNS_07,
#endif
#ifdef XSNS_08
XSNS_08,
#endif
#ifdef XSNS_09
XSNS_09,
#endif
#ifdef XSNS_10
XSNS_10,
#endif
#ifdef XSNS_11
XSNS_11,
#endif
#ifdef XSNS_12
XSNS_12,
#endif
#ifdef XSNS_13
XSNS_13,
#endif
#ifdef XSNS_14
XSNS_14,
#endif
#ifdef XSNS_15
XSNS_15,
#endif
#ifdef XSNS_16
XSNS_16,
#endif
#ifdef XSNS_17
XSNS_17,
#endif
#ifdef XSNS_18
XSNS_18,
#endif
#ifdef XSNS_19
XSNS_19,
#endif
#ifdef XSNS_20
XSNS_20,
#endif
#ifdef XSNS_21
XSNS_21,
#endif
#ifdef XSNS_22
XSNS_22,
#endif
#ifdef XSNS_23
XSNS_23,
#endif
#ifdef XSNS_24
XSNS_24,
#endif
#ifdef XSNS_25
XSNS_25,
#endif
#ifdef XSNS_26
XSNS_26,
#endif
#ifdef XSNS_27
XSNS_27,
#endif
#ifdef XSNS_28
XSNS_28,
#endif
#ifdef XSNS_29
XSNS_29,
#endif
#ifdef XSNS_30
XSNS_30,
#endif
#ifdef XSNS_31
XSNS_31,
#endif
#ifdef XSNS_32
XSNS_32,
#endif
#ifdef XSNS_33
XSNS_33,
#endif
#ifdef XSNS_34
XSNS_34,
#endif
#ifdef XSNS_35
XSNS_35,
#endif
#ifdef XSNS_36
XSNS_36,
#endif
#ifdef XSNS_37
XSNS_37,
#endif
#ifdef XSNS_38
XSNS_38,
#endif
#ifdef XSNS_39
XSNS_39,
#endif
#ifdef XSNS_40
XSNS_40,
#endif
#ifdef XSNS_41
XSNS_41,
#endif
#ifdef XSNS_42
XSNS_42,
#endif
#ifdef XSNS_43
XSNS_43,
#endif
#ifdef XSNS_44
XSNS_44,
#endif
#ifdef XSNS_45
XSNS_45,
#endif
#ifdef XSNS_46
XSNS_46,
#endif
#ifdef XSNS_47
XSNS_47,
#endif
#ifdef XSNS_48
XSNS_48,
#endif
#ifdef XSNS_49
XSNS_49,
#endif
#ifdef XSNS_50
XSNS_50,
#endif
// Optional user defined sensors in range 91 - 99
#ifdef XSNS_91
XSNS_91,
#endif
#ifdef XSNS_92
XSNS_92,
#endif
#ifdef XSNS_93
XSNS_93,
#endif
#ifdef XSNS_94
XSNS_94,
#endif
#ifdef XSNS_95
XSNS_95
#endif
};
/*********************************************************************************************\
* Xsns sensor control
\*********************************************************************************************/
bool XsnsEnabled(uint8_t sns_index)
{
if (sns_index < sizeof(kXsnsList)) {
#ifdef XFUNC_PTR_IN_ROM
uint8_t index = pgm_read_byte(kXsnsList + sns_index);
#else
uint8_t index = kXsnsList[sns_index];
#endif
return bitRead(Settings.sensors[index / 32], index % 32);
}
return 1;
}
bool XsnsPresent(uint8_t sns_index)
{
uint8_t index = 0;