From e40bed4b25c0da6e9482ece57ed1081edc6f84f1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 5 Apr 2021 15:32:31 +0200 Subject: [PATCH] Add support for dummy energy monitor Add support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` (#10640) --- CHANGELOG.md | 3 +- RELEASENOTES.md | 1 + tasmota/my_user_config.h | 1 + tasmota/tasmota_template.h | 2 +- tasmota/xnrg_20_dummy.ino | 147 +++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 tasmota/xnrg_20_dummy.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f70e9bd9..f6baaaa56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Support for multiple CCS811 sensors with baseline control (USE_CCS811_V2) by clanganke (#10858) - Berry add ``gpio`` module - Berry add ``light`` module +- Support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` (#10640) ### Changed - PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 @@ -198,7 +199,7 @@ All notable changes to this project will be documented in this file. - Milliseconds to console output (#10152) - Support for P9813 RGB Led MOSFET controller (#10104) - Support for GPIO option selection -- Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs (#10196) +- Gpio ``Option A1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs (#10196) - Support for FTC532 8-button touch controller by Peter Franck (#10222) - Support character `#` to be replaced by `space`-character in command ``Publish`` topic (#10258) - BSSID and Signal Strength Indicator to GUI wifi scan result (#10253) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c0633b64f..55c397eac 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -89,6 +89,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan BubĂ­k [#11145](https://github.com/arendst/Tasmota/issues/11145) - Support for XPT2046 touch screen digitizer on ILI9341 display by nonix [#11159](https://github.com/arendst/Tasmota/issues/11159) - Support for zigbee lumi.sensor_wleak [#11200](https://github.com/arendst/Tasmota/issues/11200) +- Support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` [#10640](https://github.com/arendst/Tasmota/issues/10640) - Support for CSE7761 energy monitor as used in ESP32 based Sonoff Dual R3 Pow [#10793](https://github.com/arendst/Tasmota/issues/10793) - Support for Frequency monitoring and zero-cross detection on CSE7761 (Sonoff Dual R3) - Support for TM1638 seven segment display by Ajith Vasudevan [#11031](https://github.com/arendst/Tasmota/issues/11031) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 456ecce7f..139f6983c 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -707,6 +707,7 @@ // -- Power monitoring sensors -------------------- #define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code) #define USE_ENERGY_POWER_LIMIT // Add additional support for Energy Power Limit detection (+1k2 code) +#define USE_ENERGY_DUMMY // Add support for dummy Energy monitor allowing user values (+0k5 code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM_AC // Add support for PZEM014,016 Energy monitor (+1k1 code) #define USE_PZEM_DC // Add support for PZEM003,017 Energy monitor (+1k1 code) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index c7d76279f..ae4741ff8 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -174,7 +174,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t data; // Allow bit manipulation using SetOption struct { // GPIO Option_A1 .. Option_A32 uint32_t pwm1_input : 1; // bit 0 (v9.2.0.1) - Option_A1 - (Light) Change PWM1 to input on power off and no fade running (1) - uint32_t spare01 : 1; // bit 1 + uint32_t dummy_energy : 1; // bit 1 (v9.3.1.2) - Option_A2 - (Energy) Enable dummy values uint32_t spare02 : 1; // bit 2 uint32_t spare03 : 1; // bit 3 uint32_t spare04 : 1; // bit 4 diff --git a/tasmota/xnrg_20_dummy.ino b/tasmota/xnrg_20_dummy.ino new file mode 100644 index 000000000..913067dc5 --- /dev/null +++ b/tasmota/xnrg_20_dummy.ino @@ -0,0 +1,147 @@ +/* + xnrg_20_dummy.ino - Dummy energy sensor support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ENERGY_SENSOR +#ifdef USE_ENERGY_DUMMY +/*********************************************************************************************\ + * Provides dummy energy monitoring + * + * User is supposed to enter valid data for Voltage, Current and Power + * Active Power is adjusted to calculated Apparent Power (=U*I) if the latter is smaller than the first + * + * Enable by selecting any GPIO as Option A2 +\*********************************************************************************************/ + +#define XNRG_20 20 + +#define NRG_DUMMY_PHASES 1 // 1 to 3 channels as x phases +#define NRG_DUMMY_U_COMMON true // Phase voltage = false, Common voltage = true +#define NRG_DUMMY_F_COMMON true // Phase frequency = false, Common frequency = true +#define NRG_DUMMY_DC false // AC = false, DC = true; + +#define NRG_DUMMY_UREF 24000 // Voltage 240.00 V (= P / I) +#define NRG_DUMMY_IREF 41666 // Current 0.417 A (= P / U) +#define NRG_DUMMY_PREF 10000 // Power 100.00 W (= U * I) +#define NRG_DUMMY_FREF 5000 // Frequency 50.00 Hz + +/********************************************************************************************/ + +void NrgDummyEverySecond(void) { + if (Energy.power_on) { // Powered on + float energy = 0; + uint32_t max_channel = (NRG_DUMMY_PHASES < 4) ? NRG_DUMMY_PHASES : 3; + for (uint32_t channel = 0; channel < max_channel; channel++) { + Energy.data_valid[channel] = 0; + Energy.voltage[channel] = ((float)Settings.energy_voltage_calibration / 100); // V + Energy.frequency[channel] = ((float)Settings.energy_frequency_calibration / 100); // Hz + Energy.active_power[channel] = ((float)Settings.energy_power_calibration / 100); // W + if (0 == Energy.active_power[channel]) { + Energy.current[channel] = 0; + } else { + Energy.current[channel] = ((float)Settings.energy_current_calibration / 100000); // A + energy += Energy.active_power[channel]; + } + } + + if (energy > 0) { + Energy.kWhtoday_delta += energy * 1000 / 36; + EnergyUpdateToday(); + } + } +} + +bool NrgDummyCommand(void) { + bool serviced = true; + + uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 + + if (CMND_POWERSET == Energy.command_code) { + if (XdrvMailbox.data_len) { + if ((value > 100) && (value < 200000)) { // Between 1.00 and 2000.00 W + Settings.energy_power_calibration = value; + } + } + } + else if (CMND_VOLTAGESET == Energy.command_code) { + if (XdrvMailbox.data_len) { + if ((value > 10000) && (value < 26000)) { // Between 100.00 and 260.00 V + Settings.energy_voltage_calibration = value; + } + } + } + else if (CMND_CURRENTSET == Energy.command_code) { + if (XdrvMailbox.data_len) { + if ((value > 1000) && (value < 1000000)) { // Between 10.00 mA and 10.00000 A + Settings.energy_current_calibration = value; + } + } + } + else if (CMND_FREQUENCYSET == Energy.command_code) { + if (XdrvMailbox.data_len) { + if ((value > 4500) && (value < 6500)) { // Between 45.00 and 65.00 Hz + Settings.energy_frequency_calibration = value; + } + } + } + else serviced = false; // Unknown command + + return serviced; +} + +void NrgDummyDrvInit(void) { + if (TasmotaGlobal.gpio_optiona.dummy_energy) { + if (HLW_PREF_PULSE == Settings.energy_power_calibration) { + Settings.energy_frequency_calibration = NRG_DUMMY_FREF; + Settings.energy_voltage_calibration = NRG_DUMMY_UREF; + Settings.energy_current_calibration = NRG_DUMMY_IREF; + Settings.energy_power_calibration = NRG_DUMMY_PREF; + } + + Energy.type_dc = NRG_DUMMY_DC; // AC = false, DC = true; + Energy.phase_count = NRG_DUMMY_PHASES; // 1 to 3 channels as x phases + Energy.voltage_common = NRG_DUMMY_U_COMMON; // Phase voltage = false, Common voltage = true + Energy.frequency_common = NRG_DUMMY_F_COMMON; // Phase frequency = false, Common frequency = true + + TasmotaGlobal.energy_driver = XNRG_20; + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xnrg20(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_ENERGY_EVERY_SECOND: + NrgDummyEverySecond(); + break; + case FUNC_COMMAND: + result = NrgDummyCommand(); + break; + case FUNC_PRE_INIT: + NrgDummyDrvInit(); + break; + } + return result; +} + +#endif // USE_ENERGY_DUMMY +#endif // USE_ENERGY_SENSOR