Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

254 lines
7.3 KiB

// -----------------------------------------------------------------------------
// V9261F based power monitor
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && V9261F_SUPPORT
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
extern "C" {
#include "libs/softuart.h"
}
class V9261FSensor : public BaseSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
V9261FSensor(): BaseSensor(), _data() {
_count = 6;
_sensor_id = SENSOR_V9261F_ID;
}
// ---------------------------------------------------------------------
void setRX(unsigned char pin_rx) {
if (_pin_rx == pin_rx) return;
_pin_rx = pin_rx;
_dirty = true;
}
void setInverted(bool inverted) {
if (_inverted == inverted) return;
_inverted = inverted;
_dirty = true;
}
// ---------------------------------------------------------------------
unsigned char getRX() {
return _pin_rx;
}
bool getInverted() {
return _inverted;
}
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
void begin() {
if (!_dirty) return;
_dirty = false;
Softuart_SetPinRx(&_serial, _pin_rx);
Softuart_Init(&_serial, V9261F_BAUDRATE, _inverted);
}
// Descriptive name of the sensor
String description() {
char buffer[28];
snprintf(buffer, sizeof(buffer), "V9261F @ SwSerial(%u,NULL)", _pin_rx);
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_pin_rx);
}
// Loop-like method, call it in your main loop
void tick() {
_read();
}
// Type for slot # index
unsigned char type(unsigned char index) {
if (index == 0) return MAGNITUDE_CURRENT;
if (index == 1) return MAGNITUDE_VOLTAGE;
if (index == 2) return MAGNITUDE_POWER_ACTIVE;
if (index == 3) return MAGNITUDE_POWER_REACTIVE;
if (index == 4) return MAGNITUDE_POWER_APPARENT;
if (index == 5) return MAGNITUDE_POWER_FACTOR;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
if (index == 0) return _current;
if (index == 1) return _voltage;
if (index == 2) return _active;
if (index == 3) return _reactive;
if (index == 4) return _apparent;
if (index == 5) return _apparent > 0 ? 100 * _active / _apparent : 100;
return 0;
}
protected:
// ---------------------------------------------------------------------
// Protected
// ---------------------------------------------------------------------
void _flush() {
while (Softuart_Available(&_serial)) {
Softuart_Read(&_serial);
}
}
void _read() {
static unsigned char state = 0;
static unsigned long last = 0;
static bool found = false;
static unsigned char index = 0;
if (state == 0) {
_flush();
found = true;
last = millis();
if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
_flush();
index = 0;
state = 1;
}
} else if (state == 1) {
while (Softuart_Available(&_serial)) {
Softuart_Read(&_serial);
if (index++ >= 7) {
_flush();
index = 0;
state = 2;
}
}
} else if (state == 2) {
while (Softuart_Available(&_serial)) {
_data[index] = Softuart_Read(&_serial);
if (index++ >= 19) {
_flush();
last = millis();
state = 3;
}
}
} else if (state == 3) {
if (_checksum()) {
_active = (double) (
(_data[3]) +
(_data[4] << 8) +
(_data[5] << 16) +
(_data[6] << 24)
) / _ratioP;
_reactive = (double) (
(_data[7]) +
(_data[8] << 8) +
(_data[9] << 16) +
(_data[10] << 24)
) / _ratioR;
_voltage = (double) (
(_data[11]) +
(_data[12] << 8) +
(_data[13] << 16) +
(_data[14] << 24)
) / _ratioV;
_current = (double) (
(_data[15]) +
(_data[16] << 8) +
(_data[17] << 16) +
(_data[18] << 24)
) / _ratioC;
if (_active < 0) _active = 0;
if (_reactive < 0) _reactive = 0;
if (_voltage < 0) _voltage = 0;
if (_current < 0) _current = 0;
_apparent = sqrt(_reactive * _reactive + _active * _active);
}
last = millis();
index = 0;
state = 4;
} else if (state == 4) {
_flush();
last = millis();
if (millis() - last > V9261F_SYNC_INTERVAL) {
state = 1;
}
}
}
bool _checksum() {
unsigned char checksum = 0;
for (unsigned char i = 0; i < 19; i++) {
checksum = checksum + _data[i];
}
checksum = ~checksum + 0x33;
return checksum == _data[19];
}
// ---------------------------------------------------------------------
unsigned int _pin_rx = V9261F_PIN;
bool _inverted = V9261F_PIN_INVERSE;
Softuart _serial;
double _active = 0;
double _reactive = 0;
double _voltage = 0;
double _current = 0;
double _apparent = 0;
double _ratioP = V9261F_POWER_FACTOR;
double _ratioC = V9261F_CURRENT_FACTOR;
double _ratioV = V9261F_VOLTAGE_FACTOR;
double _ratioR = V9261F_RPOWER_FACTOR;
unsigned char _data[24];
};
#endif // SENSOR_SUPPORT && V9261F_SUPPORT