-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathbecky.device.nut
124 lines (98 loc) · 3.18 KB
/
becky.device.nut
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
// NOTE:
// This example uses Input/Output Ports, which have been replaced by Agents and HTTP request-based communication.
// This code will not work as currently written, but remains primarily as a reference for older designs.
// Examples of the current communication architecture are available at http://electricimp.com/docs/examples/
// outlet controller and power sensor
// http://www.analog.com/en/analog-to-digital-converters/energy-measurement/ade7953/products/product.html
local function read(i2c, addr) {
// registers 0-ff are 8 bit, 100-1ff are 16 bit, 200-2ff are 24 bit and
// 300-3ff are 32 bit
local res = i2c.read(0x70, format("%c%c", addr>>8, addr&0xff), 1+(addr>>8));
local resv = 0;
if (res != null) {
foreach (b in res) resv = (resv<<8) + b;
return resv;
}
return 0;
}
// Signed read
local function reads(i2c, addr) {
local r = read(i2c, addr);
local length = 1 + (addr>>8);
local mask = 1<<(length<<3);
if (r > (mask>>1)) return r-mask;
return r;
}
local function write(i2c, addr, data) {
// registers 0-ff are 8 bit, 100-1ff are 16 bit, 200-2ff are 24 bit and
// 300-3ff are 32 bit
local length = 1 + (addr>>8);
i2c.write(0x70, format("%c%c", addr>>8, addr&0xff) + data);
}
// Pin1 = relay off (drive high for 100ms)
// Pin5 = relay on (drive high for 100ms)
// Pin7 = 5v supply monitor (divided by two)
// Pin8/9 = I2C
relay0 <- hardware.pin1;
relay1 <- hardware.pin5;
i2c <- hardware.i2c89;
relay0.configure(DIGITAL_OUT);
relay1.configure(DIGITAL_OUT);
i2c.configure(CLOCK_SPEED_400_KHZ);
// configure current gain to 1 (500mV swing max)
write(i2c, 0x008, "\x01");
// configure voltage gain to 1 (500mV swing max)
write(i2c, 0x007, "\x01");
// configure active energy line accumulation mode on current channel A, clear on read
write(i2c, 0x004, "\x41");
local function pulse(r) {
r.write(1);
imp.sleep(0.1);
r.write(0);
}
// We don't know if we were on or off
switchstate <- -1;
watts <- 0.0;
// Output: power being used
power <- OutputPort("Power Used");
// Input: relay control
class Control extends InputPort {
name = "On/Off"
function set(v) {
if (v != switchstate) pulse(v==0?relay0:relay1);
switchstate = v;
sendstate();
}
}
function sendstate() {
local s=format("%6.1f W", watts);
if (switchstate == 1) {
power.set(watts);
} else {
s="off";
power.set(0);
}
server.show(s)
}
function reporter() {
imp.wakeup(2.0, reporter);
local awatt = reads(i2c, 0x0212);
// Debug if we want more detail
//local cyclecount = read(i2c, 0x010e);
//local vrms = read(i2c, 0x21c);
//server.log(format("vrms = %d cyclecount = %d awatt=%d", vrms, cyclecount, awatt));
// No negative readings
if (awatt < 0.0) awatt = 0.0;
// Scaling
watts = (286.0 * awatt) / 236000.0;
watts = math.floor(watts * 10 + 0.5) / 10.0;
// If we just rebooted and don't know if we're on or off, work it out from power draw
if (switchstate == -1) {
switchstate = (watts > 0.5)?1:0;
}
sendstate();
}
// Appear on planner
imp.configure("Plugtop", [Control()], [power]);
// Start reporting
reporter();