Skip to content

Commit

Permalink
sensor/emon: refactoring (#2213)
Browse files Browse the repository at this point in the history
- Update sensor classes to support a generic way to store energy values
- Update sensor conversion code to deal with units and not magnitudes
- Add magnitude<->unit for sensors, generic way of defining used unit. Convert from sensor magnitude unit to the one used for display.
- Reset energy value based on index through external means (MQTT, HTTP)
- Rework energy timestamping, update webui with 'last saved' value

While this solves the energy conversion issues and we are finally seeing the real value, what I don't really like:
- KilowattHour and WattHour are separate enum tags, thus sort-of are different types altogether
- Conversion code in Energy object should probably use some generic 'ratio' calculation? (https://en.cppreference.com/w/cpp/numeric/ratio/ratio)
- We are still using runtime checks to do calculations and depend that sensor outputs only one specific value type.

Consider this a fix for energy display / storage and preliminary work on sensor.ino
Further sensor refactoring... soon.
  • Loading branch information
mcspr authored Apr 7, 2020
1 parent 49b6d35 commit cae50fa
Show file tree
Hide file tree
Showing 61 changed files with 5,976 additions and 5,298 deletions.
24 changes: 17 additions & 7 deletions code/espurna/config/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,15 @@
// UNITS
//------------------------------------------------------------------------------

#define POWER_WATTS 0
#define POWER_KILOWATTS 1
#define POWER_WATTS sensor::Unit::Watt
#define POWER_KILOWATTS sensor::Unit::Kilowatt

#define ENERGY_JOULES 0
#define ENERGY_KWH 1
#define ENERGY_JOULES sensor::Unit::Joule
#define ENERGY_KWH sensor::Unit::KilowattHour

#define TMP_CELSIUS 0
#define TMP_FAHRENHEIT 1
#define TMP_KELVIN 2
#define TMP_CELSIUS sensor::Unit::Celcius
#define TMP_FAHRENHEIT sensor::Unit::Farenheit
#define TMP_KELVIN sensor::Unit::Kelvin

//--------------------------------------------------------------------------------
// Sensor ID
Expand Down Expand Up @@ -371,6 +371,16 @@

#define MAGNITUDE_MAX 32

#define SENSOR_ERROR_OK 0 // No error
#define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range
#define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up
#define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
#define SENSOR_ERROR_UNKNOWN_ID 4 // Sensor did not report a known ID
#define SENSOR_ERROR_CRC 5 // Sensor data corrupted
#define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
#define SENSOR_ERROR_GPIO_USED 7 // The GPIO is already in use
#define SENSOR_ERROR_CALIBRATION 8 // Calibration error or Not calibrated
#define SENSOR_ERROR_OTHER 99 // Any other error
//------------------------------------------------------------------------------
// Telnet server
//------------------------------------------------------------------------------
Expand Down
Binary file modified code/espurna/data/index.all.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.sensor.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.thermostat.html.gz
Binary file not shown.
1 change: 1 addition & 0 deletions code/espurna/espurna.ino
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "rpc.h"
#include "rpnrules.h"
#include "rtcmem.h"
#include "sensor.h"
#include "thermostat.h"
#include "tuya.h"
#include "web.h"
Expand Down
10 changes: 5 additions & 5 deletions code/espurna/filters/BaseFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
class BaseFilter {

public:
virtual void add(double value);
virtual unsigned char count();
virtual void reset();
virtual double result();
virtual void resize(unsigned char size);
virtual void add(double value) = 0;
virtual unsigned char count() = 0;
virtual void reset() = 0;
virtual double result() = 0;
virtual void resize(unsigned char size) = 0;
unsigned char size() { return _size; };

protected:
Expand Down
40 changes: 40 additions & 0 deletions code/espurna/filters/SumFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// -----------------------------------------------------------------------------
// Sum Filter
// Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------

#if SENSOR_SUPPORT

#pragma once

#include "BaseFilter.h"

class SumFilter : public BaseFilter {

public:

void add(double value) {
_value += value;
}

unsigned char count() {
return 1;
}

void reset() {
_value = 0.0;
}

double result() {
return _value;
}

void resize(unsigned char size) {}

protected:

double _value = 0;

};

#endif // SENSOR_SUPPORT
2 changes: 2 additions & 0 deletions code/espurna/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>

#include "libs/BasePin.h"

constexpr const size_t GpioPins = 17;

// real hardware pin
class GpioPin final : virtual public BasePin {
public:
Expand Down
10 changes: 4 additions & 6 deletions code/espurna/gpio.ino
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@ inline int GpioPin::digitalRead() {

// --------------------------------------------------------------------------

constexpr const size_t GPIO_PINS = 17;

std::bitset<GPIO_PINS> _gpio_locked;
std::bitset<GPIO_PINS> _gpio_available;
std::bitset<GpioPins> _gpio_locked;
std::bitset<GpioPins> _gpio_available;

bool gpioValid(unsigned char gpio) {
if (gpio >= GPIO_PINS) return false;
if (gpio >= GpioPins) return false;

return _gpio_available.test(gpio);
}
Expand Down Expand Up @@ -82,7 +80,7 @@ void gpioSetup() {
);

// TODO: GPIO16 is only for basic I/O, gpioGetLock before attachInterrupt should check for that
for (unsigned char pin=0; pin < GPIO_PINS; ++pin) {
for (unsigned char pin=0; pin < GpioPins; ++pin) {
if (pin <= 5) _gpio_available.set(pin);
if (((pin == 9) || (pin == 10)) && (esp8285)) _gpio_available.set(pin);
if (12 <= pin && pin <= 16) _gpio_available.set(pin);
Expand Down
10 changes: 4 additions & 6 deletions code/espurna/homeassistant.ino
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,10 @@ void _haSendDiscovery() {

#if SENSOR_SUPPORT

void _haSendMagnitude(unsigned char i, JsonObject& config) {

unsigned char type = magnitudeType(i);
config["name"] = _haFixName(getSetting("hostname") + String(" ") + magnitudeTopic(type));
config["state_topic"] = mqttTopic(magnitudeTopicIndex(i).c_str(), false);
config["unit_of_measurement"] = magnitudeUnits(type);
void _haSendMagnitude(unsigned char index, JsonObject& config) {
config["name"] = _haFixName(getSetting("hostname") + String(" ") + magnitudeTopic(magnitudeType(index)));
config["state_topic"] = mqttTopic(magnitudeTopicIndex(index).c_str(), false);
config["unit_of_measurement"] = magnitudeUnits(index);
}

void ha_discovery_t::prepareMagnitudes(ha_config_t& config) {
Expand Down
14 changes: 10 additions & 4 deletions code/espurna/rtcmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#define RTCMEM_BLOCKS 96u

// Change this when modifying RtcmemData
#define RTCMEM_MAGIC 0x45535075
#define RTCMEM_MAGIC 0x46535076

// XXX: All access must be 4-byte aligned and always at full length.
//
// For example, using bitfields / inner structs / etc:
// Exactly like PROGMEM works. For example, using bitfields / inner structs / etc:
// ...
// uint32_t a : 8;
// uint32_t b : 8;
Expand All @@ -38,13 +37,20 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
// mem->d = 4;

// TODO replace with custom memory segment in ldscript?
// `magic` would need to be tracked differently

struct RtcmemEnergy {
uint32_t kwh;
uint32_t ws;
};

struct RtcmemData {
uint32_t magic;
uint32_t sys;
uint32_t relay;
uint32_t mqtt;
uint64_t light;
double energy[4];
RtcmemEnergy energy[4];
};

static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
Expand Down
Loading

0 comments on commit cae50fa

Please sign in to comment.