Support for pulse meter

This commit is contained in:
Gunnar Skjold
2024-01-18 07:57:56 +01:00
parent e7ca408baa
commit 87ddf00afa
8 changed files with 244 additions and 52 deletions

View File

@@ -30,11 +30,12 @@ ADC_MODE(ADC_VCC);
#define WDT_TIMEOUT 60
#define METER_SOURCE_NONE 0
#define METER_SOURCE_SERIAL 1
#define METER_SOURCE_GPIO 1
#define METER_SOURCE_MQTT 2
#define METER_SOURCE_ESPNOW 3
#define METER_PARSER_PASSIVE 0
#define METER_PARSER_PULSE 2
#define METER_PARSER_KAMSTRUP 9
#define METER_ERROR_NO_DATA 90
@@ -79,6 +80,7 @@ ADC_MODE(ADC_VCC);
#include "MeterCommunicator.h"
#include "PassiveMeterCommunicator.h"
#include "KamstrupPullCommunicator.h"
#include "PulseMeterCommunicator.h"
#include "Uptime.h"
@@ -172,6 +174,7 @@ RealtimePlot rtp;
MeterCommunicator* mc = NULL;
PassiveMeterCommunicator* passiveMc = NULL;
KamstrupPullCommunicator* kamstrupMc = NULL;
PulseMeterCommunicator* pulseMc = NULL;
bool networkConnected = false;
bool setupMode = false;
@@ -193,6 +196,9 @@ bool handleVoltageCheck();
bool readHanPort();
void errorBlink();
uint8_t pulses = 0;
void onPulse();
#if defined(ESP32)
uint8_t dnsState = 0;
ip_addr_t dns0;
@@ -682,9 +688,13 @@ void loop() {
if(config.isMeterChanged()) {
config.getMeterConfig(meterConfig);
if(meterConfig.source = METER_SOURCE_SERIAL) {
if(meterConfig.source = METER_SOURCE_GPIO) {
switch(meterConfig.parser) {
case METER_PARSER_PASSIVE:
if(pulseMc != NULL) {
delete pulseMc;
pulseMc = NULL;
}
if(kamstrupMc != NULL) {
delete(kamstrupMc);
kamstrupMc = NULL;
@@ -697,6 +707,10 @@ void loop() {
mc = passiveMc;
break;
case METER_PARSER_KAMSTRUP:
if(pulseMc != NULL) {
delete pulseMc;
pulseMc = NULL;
}
if(passiveMc != NULL) {
delete(passiveMc);
passiveMc = NULL;
@@ -708,6 +722,23 @@ void loop() {
hwSerial = kamstrupMc->getHwSerial();
mc = kamstrupMc;
break;
case METER_PARSER_PULSE:
if(kamstrupMc != NULL) {
delete(kamstrupMc);
kamstrupMc = NULL;
}
if(passiveMc != NULL) {
delete(passiveMc);
passiveMc = NULL;
}
if(pulseMc == NULL) {
pulseMc = new PulseMeterCommunicator(&Debug);
}
pulseMc->configure(meterConfig, tz);
attachInterrupt(digitalPinToInterrupt(meterConfig.rxPin), onPulse, meterConfig.rxPinPullup ? RISING : FALLING);
mc = pulseMc;
break;
default:
debugE_P(PSTR("Unknown meter parser selected: %d"), meterConfig.parser);
}
@@ -1092,6 +1123,10 @@ void toggleSetupMode() {
bool readHanPort() {
if(mc == NULL) return false;
if(pulseMc != NULL) {
pulseMc->onPulse(pulses);
pulses = 0;
}
if(!mc->loop()) {
meterState.setLastError(mc->getLastError());
return false;
@@ -1818,3 +1853,7 @@ void configFileParse() {
config.save();
LittleFS.end();
}
void IRAM_ATTR onPulse() {
pulses++;
}

16
src/ImpulseAmsData.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "ImpulseAmsData.h"
#include "Uptime.h"
ImpulseAmsData::ImpulseAmsData(AmsData& state, uint16_t pulsePerKwh, uint8_t pulses) {
listType = 1;
if(pulses > 0) {
lastUpdateMillis = millis64();
uint64_t lastStateMillis = state.getLastUpdateMillis();
if(lastStateMillis > 0) {
uint64_t ms = (lastUpdateMillis - lastStateMillis) / pulses;
activeImportPower = (1000.0 / pulsePerKwh) / (((float) ms) / 3600000.0);
}
} else {
lastUpdateMillis = state.getLastUpdateMillis();
}
}

11
src/ImpulseAmsData.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _IMPULSEAMSDATA_H
#define _IMPULSEAMSDATA_H
#include "AmsData.h"
class ImpulseAmsData : public AmsData {
public:
ImpulseAmsData(AmsData &state, uint16_t pulsePerKwh, uint8_t pulses);
};
#endif

View File

@@ -0,0 +1,78 @@
#include "PulseMeterCommunicator.h"
#include "Uptime.h"
PulseMeterCommunicator::PulseMeterCommunicator(RemoteDebug* debugger) {
this->debugger = debugger;
}
void PulseMeterCommunicator::configure(MeterConfig& meterConfig, Timezone* tz) {
this->meterConfig = meterConfig;
this->configChanged = false;
this->tz = tz;
setupGpio();
}
bool PulseMeterCommunicator::loop() {
return updated || !initialized;
}
AmsData* PulseMeterCommunicator::getData(AmsData& meterState) {
if(!initialized) {
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Initializing pulse meter state\n"));
state.apply(meterState);
initialized = true;
return NULL;
}
updated = false;
AmsData* ret = new AmsData();
ret->apply(state);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("Returning AMS data, list type: %d\n"), ret->getListType());
return ret;
}
int PulseMeterCommunicator::getLastError() {
return 0;
}
bool PulseMeterCommunicator::isConfigChanged() {
return this->configChanged;
}
void PulseMeterCommunicator::getCurrentConfig(MeterConfig& meterConfig) {
meterConfig = this->meterConfig;
}
void PulseMeterCommunicator::setupGpio() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Setting up Pulse Meter GPIO, rx: %d, tx: %d\n"), meterConfig.rxPin, meterConfig.txPin);
if(meterConfig.rxPin != NOT_A_PIN) {
pinMode(meterConfig.rxPin, meterConfig.rxPinPullup ? INPUT_PULLUP : INPUT_PULLDOWN);
}
if(meterConfig.txPin != NOT_A_PIN) {
pinMode(meterConfig.txPin, OUTPUT);
digitalWrite(meterConfig.txPin, HIGH);
}
}
void PulseMeterCommunicator::onPulse(uint8_t pulses) {
uint64_t now = millis64();
if(initialized && pulses == 0) {
if(now - lastUpdate > 10000) {
ImpulseAmsData update(state, meterConfig.baud, pulses);
state.apply(update);
updated = true;
lastUpdate = now;
}
return;
}
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("PULSE\n"));
if(!initialized) {
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Pulse communicator not initialized\n"));
return;
}
ImpulseAmsData update(state, meterConfig.baud, pulses);
state.apply(update);
updated = true;
lastUpdate = now;
}

View File

@@ -0,0 +1,41 @@
/**
* @copyright Utilitech AS 2024
* License: Fair Source
*
*/
#ifndef _PULSEMETERCOMMUNICATOR_H
#define _PULSEMETERCOMMUNICATOR_H
#include "MeterCommunicator.h"
#include "RemoteDebug.h"
#include "AmsConfiguration.h"
#include "Timezone.h"
#include "ImpulseAmsData.h"
class PulseMeterCommunicator : public MeterCommunicator {
public:
PulseMeterCommunicator(RemoteDebug* debugger);
void configure(MeterConfig&, Timezone*);
bool loop();
AmsData* getData(AmsData& meterState);
int getLastError();
bool isConfigChanged();
void getCurrentConfig(MeterConfig& meterConfig);
void onPulse(uint8_t pulses);
protected:
RemoteDebug* debugger = NULL;
MeterConfig meterConfig;
bool configChanged = false;
Timezone* tz;
bool updated = false;
bool initialized = false;
AmsData state;
uint64_t lastUpdate = 0;
void setupGpio();
};
#endif