comparison service/piNode/devices.py @ 221:666e0e756ce6

piNode support for temp sensors. proper hostname lookup Ignore-this: a68c3319bffb16c55cbb5f329118f0a4
author drewp@bigasterisk.com
date Mon, 18 Jan 2016 22:43:22 -0800
parents fb23df31b642
children 4e91f3ec460b
comparison
equal deleted inserted replaced
220:fb23df31b642 221:666e0e756ce6
1 from __future__ import division 1 from __future__ import division
2 2
3 import time, logging 3 import time, logging, os
4 from rdflib import Namespace, RDF, URIRef, Literal 4 from rdflib import Namespace, RDF, URIRef, Literal
5 5
6 try: 6 try:
7 import pigpio 7 import pigpio
8 except ImportError: 8 except ImportError:
9 pigpio = None 9 pigpio = None
10 10 import w1thermsensor
11
12 import sys
11 13
12 log = logging.getLogger() 14 log = logging.getLogger()
13 ROOM = Namespace('http://projects.bigasterisk.com/room/') 15 ROOM = Namespace('http://projects.bigasterisk.com/room/')
14 XSD = Namespace('http://www.w3.org/2001/XMLSchema#') 16 XSD = Namespace('http://www.w3.org/2001/XMLSchema#')
17 RDFS = Namespace('http://www.w3.org/2000/01/rdf-schema#')
15 18
16 class DeviceType(object): 19 class DeviceType(object):
17 deviceType = None 20 deviceType = NotImplementedError
18 @classmethod 21 @classmethod
19 def findInstances(cls, graph, board, pi): 22 def findInstances(cls, graph, board, pi):
20 """ 23 """
21 return any number of instances of this class for all the separately 24 return any number of instances of this class for all the separately
22 controlled devices on the board. Two LEDS makes two instances, 25 controlled devices on the board. Two LEDS makes two instances,
23 but two sensors on the same onewire bus makes only one device 26 but two sensors on the same onewire bus makes only one device
24 (which yields more statements). 27 (which yields more statements).
25 """ 28 """
29 log.debug("graph has any connected devices of type %s?", cls.deviceType)
26 for row in graph.query("""SELECT ?dev ?gpioNumber WHERE { 30 for row in graph.query("""SELECT ?dev ?gpioNumber WHERE {
27 ?board :hasPin ?pin . 31 ?board :hasPin ?pin .
28 ?pin :gpioNumber ?gpioNumber; 32 ?pin :gpioNumber ?gpioNumber;
29 :connectedTo ?dev . 33 :connectedTo ?dev .
30 ?dev a ?thisType . 34 ?dev a ?thisType .
31 } ORDER BY ?dev""", 35 } ORDER BY ?dev""",
32 initBindings=dict(board=board, 36 initBindings=dict(board=board,
33 thisType=cls.deviceType), 37 thisType=cls.deviceType)):
34 initNs={'': ROOM}):
35 yield cls(graph, row.dev, pi, int(row.gpioNumber)) 38 yield cls(graph, row.dev, pi, int(row.gpioNumber))
36 39
37 def __init__(self, graph, uri, pi, pinNumber): 40 def __init__(self, graph, uri, pi, pinNumber):
38 self.graph, self.uri, self.pi = graph, uri, pi 41 self.graph, self.uri, self.pi = graph, uri, pi
39 self.pinNumber = pinNumber 42 self.pinNumber = pinNumber
89 _knownTypes.add(deviceType) 92 _knownTypes.add(deviceType)
90 return deviceType 93 return deviceType
91 94
92 @register 95 @register
93 class MotionSensorInput(DeviceType): 96 class MotionSensorInput(DeviceType):
97 # compare motion sensor lib at http://pythonhosted.org/gpiozero/inputs/
98 # which is a bit fancier
94 deviceType = ROOM['MotionSensor'] 99 deviceType = ROOM['MotionSensor']
95 100
96 def setup(self): 101 def setup(self):
97 self.pi.set_mode(17, pigpio.INPUT) 102 self.pi.set_mode(17, pigpio.INPUT)
98 self.pi.set_pull_up_down(17, pigpio.PUD_DOWN) 103 self.pi.set_pull_up_down(17, pigpio.PUD_DOWN)
124 129
125 130
126 @register 131 @register
127 class RgbStrip(DeviceType): 132 class RgbStrip(DeviceType):
128 """3 PWMs for r/g/b on a strip""" 133 """3 PWMs for r/g/b on a strip"""
134 # pigpio daemon is working fine, but
135 # https://github.com/RPi-Distro/python-gpiozero/blob/59ba7154c5918745ac894ea03503667d6473c760/gpiozero/output_devices.py#L213
136 # can also apparently do PWM
129 deviceType = ROOM['RgbStrip'] 137 deviceType = ROOM['RgbStrip']
130 138
131 @classmethod 139 @classmethod
132 def findInstances(cls, graph, board, pi): 140 def findInstances(cls, graph, board, pi):
133 for row in graph.query("""SELECT DISTINCT ?dev ?r ?g ?b WHERE { 141 for row in graph.query("""SELECT DISTINCT ?dev ?r ?g ?b WHERE {
181 'pred': ROOM['color'], 189 'pred': ROOM['color'],
182 }] 190 }]
183 191
184 192
185 @register 193 @register
194 class TempHumidSensor(DeviceType):
195 deviceType = ROOM['TempHumidSensor']
196
197 def __init__(self, *a, **kw):
198 DeviceType.__init__(self, *a, **kw)
199 sys.path.append('/opt/pigpio/EXAMPLES/Python/DHT22_AM2302_SENSOR')
200 import DHT22
201 self.sensor = DHT22.sensor(self.pi, self.pinNumber)
202
203 def poll(self):
204 self.sensor.trigger()
205 humid, tempC = self.sensor.humidity(), self.sensor.temperature()
206
207 stmts = set()
208 if humid is not None:
209 stmts.add((self.uri, ROOM['humidity'], Literal(humid)))
210 else:
211 stmts.add((self.uri, RDFS['comment'],
212 Literal('DHT read returned None')))
213 if tempC is not None:
214 stmts.add((self.uri, ROOM['temperatureF'],
215 Literal(tempC * 9 / 5 + 32)))
216 else:
217 stmts.add((self.uri, RDFS['comment'],
218 Literal('DHT read returned None')))
219 return stmts
220
221 def watchPrefixes(self):
222 return [
223 (self.uri, ROOM['temperatureF']),
224 (self.uri, ROOM['humidity']),
225 ]
226
227 @register
228 class OneWire(DeviceType):
229 """
230 Also see /my/proj/ansible/roles/raspi_io_node/tasks/main.yml for
231 some system config that contains the pin number that you want to
232 use for onewire. The pin number in this config is currently ignored.
233 """
234 deviceType = ROOM['OneWire']
235 # deliberately written like arduinoNode's one for an easier merge.
236 def __init__(self, *a, **kw):
237 DeviceType.__init__(self, *a, **kw)
238 log.info("scan for w1 devices")
239 self._sensors = w1thermsensor.W1ThermSensor.get_available_sensors()
240 for s in self._sensors:
241 # Something looks different about these ids
242 # ('000003a5a94c') vs the ones I get from arduino
243 # ('2813bea50300003d'). Not sure if I'm parsing them
244 # differently or what.
245 s.uri = URIRef(os.path.join(self.uri, 'dev-%s' % s.id))
246 log.info(' found temperature sensor %s' % s.uri)
247
248 def poll(self):
249 try:
250 stmts = []
251 for sensor in self._sensors:
252 stmts.append((self.uri, ROOM['connectedTo'], sensor.uri))
253 try:
254 tempF = sensor.get_temperature(sensor.DEGREES_F)
255 stmts.append((sensor.uri, ROOM['temperatureF'],
256 Literal(tempF)))
257 except w1thermsensor.core.SensorNotReadyError as e:
258 log.warning(e)
259
260 return stmts
261 except Exception as e:
262 log.error(e)
263 os.abort()
264
265 def watchPrefixes(self):
266 return [(s.uri, ROOM['temperatureF']) for s in self._sensors]
267
268
269 @register
186 class LedOutput(DeviceType): 270 class LedOutput(DeviceType):
187 deviceType = ROOM['LedOutput'] 271 deviceType = ROOM['LedOutput']
188 272
189 def setup(self): 273 def setup(self):
190 self.pi.set_mode(self.pinNumber, pigpio.OUTPUT) 274 self.pi.set_mode(self.pinNumber, pigpio.OUTPUT)
217 @classmethod 301 @classmethod
218 def findInstances(cls, graph, board, pi): 302 def findInstances(cls, graph, board, pi):
219 for row in graph.query('''SELECT DISTINCT ?uri WHERE { 303 for row in graph.query('''SELECT DISTINCT ?uri WHERE {
220 ?board :onboardDevice ?uri . 304 ?board :onboardDevice ?uri .
221 ?uri a :OnboardTemperature . 305 ?uri a :OnboardTemperature .
222 }'''): 306 }''', initBindings=dict(board=board)):
223 yield cls(graph, row.uri, pi, pinNumber=None) 307 yield cls(graph, row.uri, pi, pinNumber=None)
224 308
225 def poll(self): 309 def poll(self):
226 milliC = open('/sys/class/thermal/thermal_zone0/temp').read().strip() 310 milliC = open('/sys/class/thermal/thermal_zone0/temp').read().strip()
227 c = float(milliC) / 1000. 311 c = float(milliC) / 1000.