-
Notifications
You must be signed in to change notification settings - Fork 319
/
_P170_HLW8012.ino
241 lines (221 loc) · 10.6 KB
/
_P170_HLW8012.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//#######################################################################################################
//#################### Plugin 170 HLW8012 AC Current and Voltage measurement sensor #####################
//#######################################################################################################
//
// This plugin is interfacing with HLW8012 IC which is use with some commercial devices:
// -- Sonoff POW
// -- ElectroDragon HLW8012 Breakout board
//
// The Sonoff POW uses the following PINs: SEL=GPIO05(D1), CF1=GPIO13(D8), CF=GPIO14(D5)
// The ED Module has pinheaders so any available PIN on the ESP8266 can be used.
//
// HLW8012 IC works with 5VDC (it seems at 3.3V is not stable in reading)
//
#ifdef PLUGIN_BUILD_TESTING
#include <HLW8012.h>
HLW8012 *Plugin_170_hlw;
#define PLUGIN_170
#define PLUGIN_ID_170 170
#define PLUGIN_170_DEBUG true //activate extra log info in the debug
#define PLUGIN_NAME_170 "Voltage & Current (AC) - HLW8012 [TESTING]"
#define PLUGIN_VALUENAME1_170 "Voltage (V)"
#define PLUGIN_VALUENAME2_170 "Current (A)"
#define PLUGIN_VALUENAME3_170 "Active Power (W)"
#define PLUGIN_VALUENAME4_170 "Power Factor (%)"
//----------------- HLW8012 Default parameters --------------------------------------------------
// Set SEL_PIN to HIGH to sample current
// This is the case for Itead's Sonoff POW, where the SEL_PIN drives a transistor that pulls down
// the SEL pin in the HLW8012 when closed
#define HLW_CURRENT_MODE HIGH
// These are the nominal values for the resistors in the circuit
#define HLW_CURRENT_RESISTOR 0.001
#define HLW_VOLTAGE_RESISTOR_UP ( 5 * 470000 ) // Real: 2280k
#define HLW_VOLTAGE_RESISTOR_DOWN ( 1000 ) // Real 1.009k
//-----------------------------------------------------------------------------------------------
byte StoredTaskIndex;
boolean Plugin_170(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_170;
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_170);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_170));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_170));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_170));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_170));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNote(string, F("Sonoff POW: 1st(SEL)=GPIO-5, 2nd(CF1)=GPIO-13, 3rd(CF)=GPIO-14"));
addFormSubHeader(string, F("Calibration Values"));
double hlwMultipliers[3];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&hlwMultipliers, sizeof(hlwMultipliers));
addFormTextBox(string, F("Current Multiplier"), F("plugin_170_currmult"), String(hlwMultipliers[0], 2), 25);
addFormTextBox(string, F("Voltage Multiplier"), F("plugin_170_voltmult"), String(hlwMultipliers[1], 2), 25);
addFormTextBox(string, F("Power Multiplier"), F("plugin_170_powmult"), String(hlwMultipliers[2], 2), 25);
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
double hlwMultipliers[3];
String tmpString, arg1;
arg1 = F("plugin_170_currmult"); tmpString = WebServer.arg(arg1);
hlwMultipliers[0] = atof(tmpString.c_str());
arg1 = F("plugin_170_voltmult"); tmpString = WebServer.arg(arg1);
hlwMultipliers[1] = atof(tmpString.c_str());
arg1 = F("plugin_170_powmult"); tmpString = WebServer.arg(arg1);
hlwMultipliers[2] = atof(tmpString.c_str());
SaveCustomTaskSettings(event->TaskIndex, (byte*)&hlwMultipliers, sizeof(hlwMultipliers));
if (PLUGIN_170_DEBUG) {
String log = F("HLW8012: Saved Calibration from Config Page");
addLog(LOG_LEVEL_INFO, log);
}
if (Plugin_170_hlw) {
Plugin_170_hlw->setCurrentMultiplier(hlwMultipliers[0]);
Plugin_170_hlw->setVoltageMultiplier(hlwMultipliers[1]);
Plugin_170_hlw->setPowerMultiplier(hlwMultipliers[2]);
}
if (PLUGIN_170_DEBUG) {
String log = F("HLW8012: Multipliers Reassigned");
addLog(LOG_LEVEL_INFO, log);
}
success = true;
break;
}
case PLUGIN_READ:
{
Plugin_170_hlw->setMode(MODE_CURRENT); delay(200); double hcurrent = Plugin_170_hlw->getCurrent();
Plugin_170_hlw->setMode(MODE_VOLTAGE); delay(200); unsigned int hvoltage = Plugin_170_hlw->getVoltage();
unsigned int hpower = Plugin_170_hlw->getActivePower();
//unsigned int happpower = Plugin_170_hlw->getApparentPower();
unsigned int hpowfact = (int) (100 * Plugin_170_hlw->getPowerFactor());
if (PLUGIN_170_DEBUG) {
String log = F("HLW8012: Read values");
log += F(" - V="); log += hvoltage;
log += F(" - A="); log += hcurrent;
log += F(" - W="); log += hpower;
log += F(" - Pf%="); log += hpowfact;
addLog(LOG_LEVEL_INFO, log);
}
UserVar[event->BaseVarIndex] = hvoltage;
UserVar[event->BaseVarIndex + 1] = hcurrent;
UserVar[event->BaseVarIndex + 2] = hpower;
UserVar[event->BaseVarIndex + 3] = hpowfact;
//Plugin_170_hlw->toggleMode();
success = true;
break;
}
case PLUGIN_INIT:
{
if (!Plugin_170_hlw)
{
Plugin_170_hlw = new HLW8012;
// This initializes the HWL8012 library.
Plugin_170_hlw->begin(Settings.TaskDevicePin3[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], Settings.TaskDevicePin1[event->TaskIndex], HLW_CURRENT_MODE, false, 1000000);
if (PLUGIN_170_DEBUG) addLog(LOG_LEVEL_INFO, F("HLW8012: Init object done"));
Plugin_170_hlw->setResistors(HLW_CURRENT_RESISTOR, HLW_VOLTAGE_RESISTOR_UP, HLW_VOLTAGE_RESISTOR_DOWN);
if (PLUGIN_170_DEBUG) addLog(LOG_LEVEL_INFO, F("HLW8012: Init Basic Resistor Values done"));
// If multipliers are empty load default ones and save all of them as "CustomTaskSettings"
double hlwMultipliers[3];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&hlwMultipliers, sizeof(hlwMultipliers));
if (hlwMultipliers[0] == 0) { hlwMultipliers[0] = Plugin_170_hlw->getCurrentMultiplier(); }
if (hlwMultipliers[1] == 0) { hlwMultipliers[1] = Plugin_170_hlw->getVoltageMultiplier(); }
if (hlwMultipliers[2] == 0) { hlwMultipliers[2] = Plugin_170_hlw->getPowerMultiplier(); }
SaveCustomTaskSettings(event->TaskIndex, (byte*)&hlwMultipliers, sizeof(hlwMultipliers));
if (PLUGIN_170_DEBUG) addLog(LOG_LEVEL_INFO, F("HLW8012: Saved Calibration after INIT"));
Plugin_170_hlw->setCurrentMultiplier(hlwMultipliers[0]);
Plugin_170_hlw->setVoltageMultiplier(hlwMultipliers[1]);
Plugin_170_hlw->setPowerMultiplier(hlwMultipliers[2]);
if (PLUGIN_170_DEBUG) addLog(LOG_LEVEL_INFO, F("HLW8012: Applied Calibration after INIT"));
StoredTaskIndex = event->TaskIndex; // store task index value in order to use it in the PLUGIN_WRITE routine
}
success = true;
break;
}
case PLUGIN_WRITE:
{
if (Plugin_170_hlw)
{
String tmpString = string;
int argIndex = tmpString.indexOf(',');
if (argIndex)
tmpString = tmpString.substring(0, argIndex);
if (tmpString.equalsIgnoreCase(F("hlwreset")))
{
Plugin_170_hlw->resetMultipliers();
Plugin170_SaveMultipliers();
if (PLUGIN_170_DEBUG) addLog(LOG_LEVEL_INFO, F("HLW8012: Reset Multipliers to DEFAULT"));
success = true;
}
if (tmpString.equalsIgnoreCase(F("hlwcalibrate")))
{
String tmpStr = string;
unsigned int CalibVolt = 0;
double CalibCurr = 0;
unsigned int CalibAcPwr = 0;
int comma1 = tmpStr.indexOf(',');
int comma2 = tmpStr.indexOf(',', comma1+1);
int comma3 = tmpStr.indexOf(',', comma2+1);
if (comma1 != 0) {
if (comma2 == 0) {
CalibVolt = tmpStr.substring(comma1+1).toInt();
} else if (comma3 == 0) {
CalibVolt = tmpStr.substring(comma1+1, comma2).toInt();
CalibCurr = atof(tmpStr.substring(comma2+1).c_str());
} else {
CalibVolt = tmpStr.substring(comma1+1, comma2).toInt();
CalibCurr = atof(tmpStr.substring(comma2+1, comma3).c_str());
CalibAcPwr = tmpStr.substring(comma3+1).toInt();
}
}
if (PLUGIN_170_DEBUG) {
String log = F("HLW8012: Calibration to values");
log += F(" - Expected-V="); log += CalibVolt;
log += F(" - Expected-A="); log += CalibCurr;
log += F(" - Expected-W="); log += CalibAcPwr;
addLog(LOG_LEVEL_INFO, log);
}
if (CalibVolt != 0) { Plugin_170_hlw->expectedVoltage(CalibVolt); }
if (CalibCurr != 0) { Plugin_170_hlw->expectedCurrent(CalibCurr); }
if (CalibAcPwr != 0) { Plugin_170_hlw->expectedActivePower(CalibAcPwr); }
// if at least one calibration value has been provided then save the new multipliers //
if ((CalibVolt + CalibCurr + CalibAcPwr) != 0) { Plugin170_SaveMultipliers(); }
success = true;
}
}
break;
}
}
return success;
}
void Plugin170_SaveMultipliers() {
double hlwMultipliers[3];
hlwMultipliers[0] = Plugin_170_hlw->getCurrentMultiplier();
hlwMultipliers[1] = Plugin_170_hlw->getVoltageMultiplier();
hlwMultipliers[2] = Plugin_170_hlw->getPowerMultiplier();
SaveCustomTaskSettings(StoredTaskIndex, (byte*)&hlwMultipliers, sizeof(hlwMultipliers));
}
#endif