-
Notifications
You must be signed in to change notification settings - Fork 0
/
RelayPowermeter.ino
259 lines (212 loc) · 6.24 KB
/
RelayPowermeter.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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Node ID
#define MY_NODE_ID 2
// Enable debug prints to serial monitor
//#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
// Enabled repeater feature for this node
//#define MY_REPEATER_FEATURE
#include <SPI.h>
#include <MySensors.h>
#include <Bounce2.h>
#include <TimeLib.h>
#include <DS3232RTC.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define RELAY_PIN 4 // Arduino Digital I/O pin number for relay
#define BUTTON_PIN 3 // Arduino Digital I/O pin number for button
#define POWERMETER_PIN A2
#define CHILD_ID_RELAY 1 // Id of the sensor child
#define CHILD_ID_POWER 2 // Id of powermeter
#define CHILD_ID_TEMP 3 // Id of internal DS3231 temperature sensor
#define RELAY_ON 1
#define RELAY_OFF 0
#define ACS712_05B 0.0264
#define ACS712_20B 0.0490
#define ACS712_30A 0.0742
class GenericHallEffectSensor
{
public:
GenericHallEffectSensor() {};
GenericHallEffectSensor(uint8_t id, float fact) { pin = id; factor = fact; }
bool operator()(float trigger) { return readAcCurrent(100) >= trigger; }
float readAcCurrent(uint16_t navg)
{
acc = 0;
for (i = 0; i<navg; i++)
{
adc = analogRead(pin) - 512;
acc += (adc*adc);
delay(1);
}
return sqrt(acc / navg)*factor;
}
float readDcCurrent(uint16_t navg)
{
average = 0;
for (i = 0; i<navg; i++)
{
average = average + (factor * analogRead(pin) - 13.513) / navg;
delay(1);
}
return average;
}
private:
uint8_t pin;
long acc, adc;
float average;
uint16_t i;
/* Factor for:
+-5 À (ACS712-05B) = 0.0264
+-20 À (ACS712-20B) = 0.0490
+-30 À (ACS712-30A) = 0.0742 */
float factor;
};
GenericHallEffectSensor io_ACS1 = GenericHallEffectSensor(POWERMETER_PIN, ACS712_20B);
Bounce debouncer = Bounce();
int oldValue=0;
bool state;
float measure;
float threshold;
bool timeReceived = false;
unsigned long lastUpdate=0, lastRequest=0;
MyMessage msg(CHILD_ID_RELAY, V_STATUS);
MyMessage msg2(CHILD_ID_POWER, V_VAR);
MyMessage msg3(CHILD_ID_TEMP, V_TEMP);
// Initialize display. Google the correct settings for your display.
// The follwoing setting should work for the recommended display in the MySensors "shop".
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
void setup()
{
// Setup the button
pinMode(BUTTON_PIN,INPUT);
// Activate internal pull-up
digitalWrite(BUTTON_PIN,HIGH);
// the function to get the time from the RTC
setSyncProvider(RTC.get);
// Request latest time from controller at startup
requestTime();
threshold = 30.0;
// After setting up the button, setup debouncer
debouncer.attach(BUTTON_PIN);
debouncer.interval(5);
// Then set relay pins in output mode
pinMode(RELAY_PIN, OUTPUT);
// Make sure relays are off when starting up
digitalWrite(RELAY_PIN, RELAY_OFF);
// Set relay to last known state (using eeprom storage)
state = loadState(CHILD_ID_RELAY);
digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
//send(msg.set(state ? true : false), true);
// initialize the lcd for 16 chars 2 lines and turn on backlight
lcd.begin(16,2);
lcd.clear();
}
void presentation() {
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Relay & Powermeter", "1.0");
// Register all sensors to gw (they will be created as child devices)
present(CHILD_ID_RELAY, S_BINARY);
present(CHILD_ID_POWER, S_POWER);
present(CHILD_ID_TEMP, S_TEMP);
}
// This is called when a new time value was received
void receiveTime(unsigned long controllerTime) {
// Ok, set incoming time
Serial.print("Time value received: ");
Serial.println(controllerTime);
RTC.set(controllerTime); // this sets the RTC to the time from controller - which we do want periodically
timeReceived = true;
}
/*
* Example on how to asynchronously check for new messages from gw
*/
void loop()
{
debouncer.update();
// Get the update value
int value = debouncer.read();
if (value != oldValue && value==0) {
send(msg.set(state ? true : false), true); // Send new state and request ack back
}
oldValue = value;
measure = io_ACS1.readAcCurrent(100);
send(msg.set(state ? true : false), true);
send(msg2.set(measure,2), false);
send(msg3.set(RTC.temperature() / 4), false);
unsigned long now = millis();
// If no time has been received yet, request it every 10 second from controller
// When time has been received, request update every hour
if ((!timeReceived && (now-lastRequest) > (10UL*1000UL))
|| (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) {
// Request time from controller.
Serial.println("requesting time");
requestTime();
lastRequest = now;
}
// Update display every second
if (now-lastUpdate > 1000) {
updateDisplay();
lastUpdate = now;
}
smartSleep(1000);
}
void receive(const MyMessage &message) {
// We only expect one type of message from controller. But we better check anyway.
/*if (message.isAck()) {
Serial.println("This is an ack from gateway");
}*/
if (message.type == V_STATUS) {
bool prevState = state;
// Change relay state
Serial.print("\nCurrent state: ");
Serial.println(state);
state = message.getBool();
if (state != prevState) {
digitalWrite(RELAY_PIN, state ? RELAY_ON : RELAY_OFF);
// Store state in eeprom
saveState(CHILD_ID_RELAY, state);
// Write some debug info
Serial.print("\nIncoming change for sensor: ");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(message.getBool());
}
}
}
void printDigits(int digits) {
if (digits < 10)
lcd.print('0');
lcd.print(digits);
}
void updateDisplay(){
tmElements_t tm;
RTC.read(tm);
lcd.home();
printDigits(tm.Hour);
lcd.print(":");
printDigits(tm.Minute);
state?lcd.print(" Relay ON "): lcd.print(" Relay OFF");
// Go to next line and print temperature
lcd.setCursor ( 0, 1 );
lcd.print("t=");
lcd.print(RTC.temperature()/4);
lcd.write(223); // Degree-sign
lcd.print("C");
// Print current
if (io_ACS1(threshold)) {
lcd.clear();
lcd.home();
lcd.println("ALARM! ");
lcd.setCursor(0, 1);
lcd.println("Current too high");
}
else {
measure = io_ACS1.readAcCurrent(1000);
//lcd.setCursor(1, 0);
lcd.print(" I=");
lcd.print(measure);
lcd.print("A");
}
}