Mercurial > code > home > repos > homeauto
annotate service/piNode/devices.py @ 1014:d27abd3b6c70
namespace
Ignore-this: 38e84ceafff99977f48d5235e77be646
darcs-hash:20151107184028-312f9-335102e8a71a7aed5d92bf1f2be3bf8ee65b89c8
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sat, 07 Nov 2015 10:40:28 -0800 |
parents | 156dda05d811 |
children | 75717a0be824 |
rev | line source |
---|---|
987 | 1 from __future__ import division |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
2 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
3 import time, logging |
987 | 4 from rdflib import Namespace, RDF, URIRef, Literal |
5 | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
6 try: |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
7 import pigpio |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
8 except ImportError: |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
9 pigpio = None |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
10 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
11 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
12 log = logging.getLogger() |
987 | 13 ROOM = Namespace('http://projects.bigasterisk.com/room/') |
1014 | 14 XSD = Namespace('http://www.w3.org/2001/XMLSchema#') |
987 | 15 |
16 class DeviceType(object): | |
17 deviceType = None | |
18 @classmethod | |
19 def findInstances(cls, graph, board, pi): | |
20 """ | |
21 return any number of instances of this class for all the separately | |
22 controlled devices on the board. Two LEDS makes two instances, | |
23 but two sensors on the same onewire bus makes only one device | |
24 (which yields more statements). | |
25 """ | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
26 for row in graph.query("""SELECT ?dev ?gpioNumber WHERE { |
987 | 27 ?board :hasPin ?pin . |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
28 ?pin :gpioNumber ?gpioNumber; |
987 | 29 :connectedTo ?dev . |
30 ?dev a ?thisType . | |
31 } ORDER BY ?dev""", | |
32 initBindings=dict(board=board, | |
33 thisType=cls.deviceType), | |
34 initNs={'': ROOM}): | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
35 yield cls(graph, row.dev, pi, int(row.gpioNumber)) |
987 | 36 |
37 def __init__(self, graph, uri, pi, pinNumber): | |
38 self.graph, self.uri, self.pi = graph, uri, pi | |
39 self.pinNumber = pinNumber | |
40 | |
41 def description(self): | |
42 return { | |
43 'uri': self.uri, | |
44 'className': self.__class__.__name__, | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
45 'pinNumber': getattr(self, 'pinNumber', None), |
987 | 46 'outputPatterns': self.outputPatterns(), |
47 'watchPrefixes': self.watchPrefixes(), | |
48 'outputWidgets': self.outputWidgets(), | |
49 } | |
50 | |
51 def watchPrefixes(self): | |
52 """ | |
53 subj,pred pairs of the statements that might be returned from | |
54 readFromPoll, so the dashboard knows what it should | |
55 watch. This should be eliminated, as the dashboard should just | |
56 always watch the whole tree of statements starting self.uri | |
57 """ | |
58 return [] | |
59 | |
60 def poll(self): | |
61 return [] # statements | |
62 | |
63 def outputPatterns(self): | |
64 """ | |
65 Triple patterns, using None as a wildcard, that should be routed | |
66 to sendOutput | |
67 """ | |
68 return [] | |
69 | |
70 def outputWidgets(self): | |
71 """ | |
72 structs to make output widgets on the dashboard. ~1 of these per | |
73 handler you have in sendOutput | |
74 """ | |
75 return [] | |
76 | |
77 def sendOutput(self, statements): | |
78 """ | |
79 If we got statements that match this class's outputPatterns, this | |
80 will be called with the statements that matched. | |
81 | |
82 Todo: it would be fine to read back confirmations or | |
83 whatever. Just need a way to collect them into graph statements. | |
84 """ | |
85 raise NotImplementedError | |
86 | |
87 _knownTypes = set() | |
88 def register(deviceType): | |
89 _knownTypes.add(deviceType) | |
90 return deviceType | |
91 | |
92 @register | |
93 class MotionSensorInput(DeviceType): | |
94 deviceType = ROOM['MotionSensor'] | |
95 | |
96 def setup(self): | |
97 self.pi.set_mode(17, pigpio.INPUT) | |
98 self.pi.set_pull_up_down(17, pigpio.PUD_DOWN) | |
99 | |
100 def poll(self): | |
101 motion = self.pi.read(17) | |
102 | |
103 return [ | |
104 (self.uri, ROOM['sees'], | |
105 ROOM['motion'] if motion else ROOM['noMotion']), | |
106 self.recentMotionStatement(motion), | |
107 ] | |
108 | |
109 def recentMotionStatement(self, motion): | |
110 if not hasattr(self, 'lastMotionTime'): | |
111 self.lastMotionTime = 0 | |
112 now = time.time() | |
113 if motion: | |
114 self.lastMotionTime = now | |
115 recentMotion = now - self.lastMotionTime < 60 * 10 | |
116 return (self.uri, ROOM['seesRecently'], | |
117 ROOM['motion'] if recentMotion else ROOM['noMotion']) | |
118 | |
119 def watchPrefixes(self): | |
120 return [ | |
121 (self.uri, ROOM['sees']), | |
122 (self.uri, ROOM['seesRecently']), | |
123 ] | |
124 | |
988
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
125 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
126 @register |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
127 class RgbStrip(DeviceType): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
128 deviceType = ROOM['RgbStrip'] |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
129 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
130 @classmethod |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
131 def findInstances(cls, graph, board, pi): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
132 for row in graph.query("""SELECT DISTINCT ?dev ?r ?g ?b WHERE { |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
133 ?board |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
134 :hasPin ?rpin; |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
135 :hasPin ?gpin; |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
136 :hasPin ?bpin . |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
137 ?dev a :RgbStrip; |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
138 :redChannel ?rpin; |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
139 :greenChannel ?gpin; |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
140 :blueChannel ?bpin . |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
141 ?rpin :gpioNumber ?r . |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
142 ?gpin :gpioNumber ?g . |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
143 ?bpin :gpioNumber ?b . |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
144 } ORDER BY ?dev""", |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
145 initBindings=dict(board=board), |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
146 initNs={'': ROOM}): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
147 log.debug('found rgb %r', row) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
148 yield cls(graph, row.dev, pi, row.r, row.g, row.b) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
149 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
150 def __init__(self, graph, uri, pi, r, g, b): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
151 self.graph, self.uri, self.pi = graph, uri, pi |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
152 self.rgb = map(int, [r, g, b]) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
153 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
154 def setup(self): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
155 for i in self.rgb: |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
156 self.pi.set_mode(i, pigpio.OUTPUT) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
157 self.pi.set_PWM_frequency(i, 200) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
158 self.pi.set_PWM_dutycycle(i, 0) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
159 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
160 def outputPatterns(self): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
161 return [(self.uri, ROOM['color'], None)] |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
162 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
163 def sendOutput(self, statements): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
164 assert len(statements) == 1 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
165 assert statements[0][:2] == (self.uri, ROOM['color']) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
166 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
167 rrggbb = statements[0][2].lstrip('#') |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
168 rgb = [int(x, 16) for x in [rrggbb[0:2], rrggbb[2:4], rrggbb[4:6]]] |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
169 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
170 for (i, v) in zip(self.rgb, rgb): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
171 self.pi.set_PWM_dutycycle(i, v) |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
172 |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
173 def outputWidgets(self): |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
174 return [{ |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
175 'element': 'output-rgb', |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
176 'subj': self.uri, |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
177 'pred': ROOM['color'], |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
178 }] |
63c172316239
get piNode working, for motionsensor at least
drewp <drewp@bigasterisk.com>
parents:
987
diff
changeset
|
179 |
1010 | 180 @register |
181 class OnboardTemperature(DeviceType): | |
182 deviceType = ROOM['OnboardTemperature'] | |
183 @classmethod | |
184 def findInstances(cls, graph, board, pi): | |
1012 | 185 for row in graph.query('''SELECT DISTINCT ?uri WHERE { |
1010 | 186 ?board :onboardDevice ?uri . |
187 ?uri a :OnboardTemperature . | |
188 }'''): | |
189 yield cls(graph, row.uri, pi, pinNumber=None) | |
190 | |
1013 | 191 def poll(self): |
1010 | 192 milliC = open('/sys/class/thermal/thermal_zone0/temp').read().strip() |
193 c = float(milliC) / 1000. | |
194 f = c * 1.8 + 32 | |
195 return [ | |
196 (self.uri, ROOM['temperatureF'], Literal(f, datatype=XSD['decimal'])), | |
197 ] | |
198 | |
199 def watchPrefixes(self): | |
200 # these uris will become dynamic! see note on watchPrefixes | |
201 # about eliminating it. | |
202 return [(self.uri, ROOM['temperatureF']), | |
203 ] | |
204 | |
987 | 205 def makeDevices(graph, board, pi): |
206 out = [] | |
207 for dt in sorted(_knownTypes, key=lambda cls: cls.__name__): | |
208 out.extend(dt.findInstances(graph, board, pi)) | |
209 return out | |
210 |