annotate service/powerInverter/powerInverter.py @ 1283:d36cd59b145a

dhcpleases partial rewrite Ignore-this: 6a2b95612f0e3a2348397f2f068e5f58 darcs-hash:c0872b2f45c0c82492615f612e9655fdc48798c5
author drewp <drewp@bigasterisk.com>
date Sat, 20 Apr 2019 23:59:04 -0700
parents 0aafd40e4afc
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
1 #!/usr/bin/python
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
2
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
3 import struct, time, sys, logging, traceback, os, cyclone.web
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
4 from serial import Serial, SerialException
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
5 from twisted.internet.task import LoopingCall
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
6 from twisted.internet import reactor
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
7
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
8 sys.path.append("/my/proj/homeauto/lib")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
9 from cycloneerr import PrettyErrorHandler
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
10 from logsetup import log
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
11
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
12 sys.path.append("/my/proj/room")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
13 from carbondata import CarbonClient
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
14
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
15 class Command(object):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
16 getVersion = 0x01
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
17 getPowerNow = 0x10
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
18
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
19 class Sleeping(ValueError):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
20 """haven't checked the spec, but this is what I get when the
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
21 inverter is off at night"""
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
22
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
23 class Comm(object):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
24 def __init__(self, device):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
25 self.ser = Serial(device, baudrate=19200)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
26
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
27 def request(self, device, number, command):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
28 self.writeMsg(device, number, command, data="\x01")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
29 return self.readMsg()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
30
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
31 def requestNumeric(self, device, number, command):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
32 buf = self.request(device, number, command)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
33 if len(buf) != 3:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
34 if buf == '\x10\x05':
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
35 raise Sleeping()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
36 raise ValueError("Expected 3 bytes for command %r, not %r" %
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
37 (command, buf))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
38 msb, lsb, exp = struct.unpack("!BBb", buf)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
39 return ((msb << 8) + lsb) * 10**exp
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
40
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
41 def writeMsg(self, device, number, command, data=""):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
42 length = len(data)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
43 commandVal = getattr(Command, command)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
44 checksum = sum(x for x in [length, device, number, commandVal] +
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
45 [ord(x) for x in data]) & 0xff
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
46 args = 0x80, 0x80, 0x80, length, device, number, commandVal, data, checksum
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
47 log.debug("Sending: %s %r", command, args)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
48 self.ser.write(struct.pack("!BBBBBBBsB", *args))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
49
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
50
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
51 def readMsg(self):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
52 log.debug("Read header..")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
53 (s1, s2, s3, length, device, number, command) = struct.unpack(
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
54 "!BBBBBBB", self.ser.read(7))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
55 if not s1 == s2 == s3 == 0x80:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
56 raise ValueError("incorrect header in response: %r" % vars())
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
57 log.debug("Read %d bytes of data", length)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
58 data = self.ser.read(length)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
59 cksum = self.ser.read(1)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
60 log.debug(" -> %r", data)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
61 return data
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
62
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
63 class Poller(object):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
64 def __init__(self, carbon):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
65 self.carbon = carbon
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
66 self.lastPollTime = 0
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
67 self.reset()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
68 LoopingCall(self.poll).start(interval=10)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
69
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
70 def reset(self):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
71 log.info("reopening serial port")
823
0aafd40e4afc move more ports to use /dev/serial/by-id/
drewp <drewp@bigasterisk.com>
parents: 809
diff changeset
72 for port in ['/dev/serial/by-id/usb-0557_2008-if00-port0']:
809
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
73 try:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
74 self.comm = Comm(port)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
75 break
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
76 except SerialException, e:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
77 pass
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
78 else:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
79 # among other things, a serial exception for too many open files
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
80 log.error(e)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
81 os.abort()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
82 log.info("version: %r", self.comm.request(device=1, number=0,
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
83 command="getVersion"))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
84
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
85 def poll(self):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
86 try:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
87 watts = self.comm.requestNumeric(device=1, number=0,
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
88 command="getPowerNow")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
89 self.carbon.send('system.house.solar.power_w', watts)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
90 except Sleeping:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
91 log.debug("sleeping")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
92 except ValueError:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
93 log.error(traceback.format_exc())
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
94 self.reset()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
95 except Exception:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
96 traceback.print_exc()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
97 os.abort()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
98 self.lastPollTime = time.time()
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
99
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
100
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
101 class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
102 def get(self):
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
103 age = time.time() - self.settings.poller.lastPollTime
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
104 if age > 12:
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
105 raise ValueError("poll data is stale. age=%s" % age)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
106
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
107 self.write("powerInverter reading from serial port and writing to graphite")
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
108
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
109 log.setLevel(logging.INFO)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
110 carbon = CarbonClient(serverHost='bang')
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
111 p = Poller(carbon)
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
112 reactor.listenTCP(9078, cyclone.web.Application([
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
113 (r'/', Index),
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
114 ], poller=p))
bebb8f7c5a3e move a bunch of services into this tree, give them all web status pages
drewp <drewp@bigasterisk.com>
parents:
diff changeset
115 reactor.run()