muwerk mupplet Sensor Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications for sensors
Loading...
Searching...
No Matches
mup_power_bl0397.h
1// power_bl0937.h
2#pragma once
3
4#include "scheduler.h"
5
6namespace ustd {
7
8#if defined(__ESP32__) || defined(__ESP__)
9#define G_INT_ATTR IRAM_ATTR
10#else
11#define G_INT_ATTR
12#endif
13
14#define USTD_MAX_BLP_PIRQS (10)
15
16volatile unsigned long blp_pirpcounter[USTD_MAX_BLP_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
17volatile unsigned long blp_plastIrqTimer[USTD_MAX_BLP_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
18volatile unsigned long blp_pbeginIrqTimer[USTD_MAX_BLP_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
19
20void G_INT_ATTR ustd_blp_pirp_master(uint8_t irqno) {
21 unsigned long curr = micros();
22 if (blp_pbeginIrqTimer[irqno] == 0)
23 blp_pbeginIrqTimer[irqno] = curr;
24 else
25 ++blp_pirpcounter[irqno];
26 blp_plastIrqTimer[irqno] = curr;
27}
28
29void G_INT_ATTR ustd_blp_pirp0() {
30 ustd_blp_pirp_master(0);
31}
32void G_INT_ATTR ustd_blp_pirp1() {
33 ustd_blp_pirp_master(1);
34}
35void G_INT_ATTR ustd_blp_pirp2() {
36 ustd_blp_pirp_master(2);
37}
38void G_INT_ATTR ustd_blp_pirp3() {
39 ustd_blp_pirp_master(3);
40}
41void G_INT_ATTR ustd_blp_pirp4() {
42 ustd_blp_pirp_master(4);
43}
44void G_INT_ATTR ustd_blp_pirp5() {
45 ustd_blp_pirp_master(5);
46}
47void G_INT_ATTR ustd_blp_pirp6() {
48 ustd_blp_pirp_master(6);
49}
50void G_INT_ATTR ustd_blp_pirp7() {
51 ustd_blp_pirp_master(7);
52}
53void G_INT_ATTR ustd_blp_pirp8() {
54 ustd_blp_pirp_master(8);
55}
56void G_INT_ATTR ustd_blp_pirp9() {
57 ustd_blp_pirp_master(9);
58}
59
60void (*ustd_blp_pirp_table[USTD_MAX_BLP_PIRQS])() = {ustd_blp_pirp0, ustd_blp_pirp1, ustd_blp_pirp2, ustd_blp_pirp3,
61 ustd_blp_pirp4, ustd_blp_pirp5, ustd_blp_pirp6, ustd_blp_pirp7,
62 ustd_blp_pirp8, ustd_blp_pirp9};
63
64unsigned long getBlpResetpIrqCount(uint8_t irqno) {
65 unsigned long count = (unsigned long)-1;
66 noInterrupts();
67 if (irqno < USTD_MAX_BLP_PIRQS) {
68 count = blp_pirpcounter[irqno];
69 blp_pirpcounter[irqno] = 0;
70 }
71 interrupts();
72 return count;
73}
74
75double getBlpResetpIrqFrequency(uint8_t irqno, unsigned long minDtUs = 50) {
76 double frequency = 0.0;
77 noInterrupts();
78 if (irqno < USTD_MAX_BLP_PIRQS) {
79 unsigned long count = blp_pirpcounter[irqno];
80 unsigned long dt = timeDiff(blp_pbeginIrqTimer[irqno], blp_plastIrqTimer[irqno]);
81 if (dt > minDtUs) { // Ignore small Irq flukes
82 frequency = (count * 500000.0) / dt; // = count/2.0*1000.0000 uS / dt; no.
83 // of waves (count/2) / dt.
84 }
85 blp_pbeginIrqTimer[irqno] = 0;
86 blp_pirpcounter[irqno] = 0;
87 blp_plastIrqTimer[irqno] = 0;
88 }
89 interrupts();
90 return frequency;
91}
92
93bool changeBlpSELi(bool bsel, uint8_t pin_sel, uint8_t irqno) {
94 digitalWrite(pin_sel, bsel);
95 getBlpResetpIrqFrequency(irqno);
96 return bsel;
97}
98
122 public:
123 String POWER_BL0937_VERSION = "0.1.0";
124 Scheduler *pSched;
125 int tID;
126
127 String name;
128 bool irqsAttached = false;
129 uint8_t pin_CF, pin_CF1, pin_SELi;
130 uint8_t irqno_CF, irqno_CF1, irqno_SELi;
131 int8_t interruptIndex_CF, interruptIndex_CF1;
132 bool bSELi = false;
133 ustd::sensorprocessor frequencyCF = ustd::sensorprocessor(8, 600, 0.1);
134 ustd::sensorprocessor frequencyCF1_I = ustd::sensorprocessor(8, 600, 0.01);
135 ustd::sensorprocessor frequencyCF1_V = ustd::sensorprocessor(8, 600, 0.1);
136 double CFfrequencyVal = 0.0;
137 double CF1_IfrequencyVal = 0.0;
138 double CF1_VfrequencyVal = 0.0;
139
140 double voltageRenormalisation = 6.221651690201113; // Empirical factors measured on Gosund-SP1
141 // to convert frequency CF to power in W.
142 double currentRenormalisation =
143 84.4444444444444411; // frequency CF1 (SELi high) to voltage (V)
144 double powerRenormalization = 0.575713594581519; // frequency CF1 (SELi low) to current (I)
145
146 double userCalibrationPowerFactor = 1.0;
147 double userCalibrationVoltageFactor = 1.0;
148 double userCalibrationCurrentFactor = 1.0;
149
150 uint8_t ipin = 255;
151
152 PowerBl0937(String name, uint8_t pin_CF, uint8_t pin_CF1, uint8_t pin_SELi,
153 int8_t interruptIndex_CF, uint8_t interruptIndex_CF1)
154 : name(name), pin_CF(pin_CF), pin_CF1(pin_CF1), pin_SELi(pin_SELi),
155 interruptIndex_CF(interruptIndex_CF), interruptIndex_CF1(interruptIndex_CF1) {
171 }
172
173 ~PowerBl0937() {
174 if (irqsAttached) {
175 detachInterrupt(irqno_CF);
176 detachInterrupt(irqno_CF1);
177 }
178 }
179
180 bool begin(Scheduler *_pSched) {
181 pSched = _pSched;
182
183 pinMode(pin_CF, INPUT_PULLUP);
184 pinMode(pin_CF1, INPUT_PULLUP);
185 pinMode(pin_SELi, OUTPUT);
186 digitalWrite(pin_SELi, bSELi);
187
188 if (interruptIndex_CF >= 0 && interruptIndex_CF < USTD_MAX_BLP_PIRQS &&
189 interruptIndex_CF1 >= 0 && interruptIndex_CF1 < USTD_MAX_BLP_PIRQS &&
190 interruptIndex_CF != interruptIndex_CF1) {
191#ifdef __ESP32__
192 irqno_CF = digitalPinToInterrupt(pin_CF);
193 irqno_CF1 = digitalPinToInterrupt(pin_CF1);
194#else
195 irqno_CF = digitalPinToInterrupt(pin_CF);
196 irqno_CF1 = digitalPinToInterrupt(pin_CF1);
197#endif
198 attachInterrupt(irqno_CF, ustd_blp_pirp_table[interruptIndex_CF], CHANGE);
199 attachInterrupt(irqno_CF1, ustd_blp_pirp_table[interruptIndex_CF1], CHANGE);
200 irqsAttached = true;
201 } else {
202 return false;
203 }
204
205 auto ft = [=]() { this->loop(); };
206 tID = pSched->add(ft, name, 2000000); // uS schedule
207
208 auto fnall = [=](String topic, String msg, String originator) {
209 this->subsMsg(topic, msg, originator);
210 };
211 pSched->subscribe(tID, name + "/power_bl0937/#", fnall);
212 return true;
213 }
214
215 void setUserCalibrationFactors(double powerFactor = 1.0, double voltageFactor = 1.0,
216 double currentFactor = 1.0) {
217 userCalibrationPowerFactor = powerFactor;
218 userCalibrationVoltageFactor = voltageFactor;
219 userCalibrationCurrentFactor = currentFactor;
220 frequencyCF.reset();
221 frequencyCF1_V.reset();
222 frequencyCF1_I.reset();
223 }
224
225 void publish_CF() {
226 char buf[32];
227 sprintf(buf, "%6.1f", CFfrequencyVal);
228 char *p1 = buf;
229 while (*p1 == ' ')
230 ++p1;
231 pSched->publish(name + "/sensor/power", p1);
232 }
233 void publish_CF1_V() {
234 char buf[32];
235 sprintf(buf, "%5.1f", CF1_VfrequencyVal);
236 char *p1 = buf;
237 while (*p1 == ' ')
238 ++p1;
239 pSched->publish(name + "/sensor/voltage", p1);
240 }
241 void publish_CF1_I() {
242 char buf[32];
243 sprintf(buf, "%5.2f", CF1_IfrequencyVal);
244 char *p1 = buf;
245 while (*p1 == ' ')
246 ++p1;
247 pSched->publish(name + "/sensor/current", p1);
248 }
249
250 void publish() {
251 publish_CF();
252 publish_CF1_V();
253 publish_CF1_I();
254 }
255
256 void loop() {
257 double watts = getBlpResetpIrqFrequency(interruptIndex_CF) / powerRenormalization *
258 userCalibrationPowerFactor;
259 if ((frequencyCF.lastVal == 0.0 && watts > 0.0) ||
260 (frequencyCF.lastVal > 0.0 && watts == 0.0))
261 frequencyCF.reset();
262 if (watts >= 0.0 && watts < 3800) {
263 if (frequencyCF.filter(&watts)) {
264 CFfrequencyVal = watts;
265 publish_CF();
266 }
267 }
268 double mfreq = getBlpResetpIrqFrequency(interruptIndex_CF1);
269 if (bSELi) {
270 double volts = mfreq / voltageRenormalisation * userCalibrationVoltageFactor;
271 if (volts < 5.0 || (volts >= 100.0 && volts < 260)) {
272 if ((frequencyCF1_V.lastVal == 0.0 && volts > 0.0) ||
273 (frequencyCF1_V.lastVal > 0.0 && volts == 0.0))
274 frequencyCF1_V.reset();
275 if (frequencyCF1_V.filter(&volts)) {
276 CF1_VfrequencyVal = volts;
277 publish_CF1_V();
278 }
279 }
280 } else {
281 double currents = mfreq / currentRenormalisation * userCalibrationCurrentFactor;
282 if (currents >= 0.0 && currents < 16.0) {
283 if ((frequencyCF1_I.lastVal == 0.0 && currents > 0.0) ||
284 (frequencyCF1_I.lastVal > 0.0 && currents == 0.0))
285 frequencyCF1_I.reset();
286 if (frequencyCF1_I.filter(&currents)) {
287 CF1_IfrequencyVal = currents;
288 publish_CF1_I();
289 }
290 }
291 }
292 bSELi = changeBlpSELi(!bSELi, pin_SELi, interruptIndex_CF1);
293 }
294
295 void subsMsg(String topic, String msg, String originator) {
296 if (topic == name + "/sensor/state/get") {
297 publish();
298 } else if (topic == name + "/sensor/power/get") {
299 publish_CF();
300 } else if (topic == name + "/sensor/voltage/get") {
301 publish_CF1_V();
302 } else if (topic == name + "/sensor/current/get") {
303 publish_CF1_I();
304 }
305 };
306}; // PowerBl0937
307
308} // namespace ustd
Power, Voltage and Current sensor BL0397.
Definition: mup_power_bl0397.h:121
PowerBl0937(String name, uint8_t pin_CF, uint8_t pin_CF1, uint8_t pin_SELi, int8_t interruptIndex_CF, uint8_t interruptIndex_CF1)
Definition: mup_power_bl0397.h:152