Mercurial > code > home > repos > homeauto
comparison service/reasoning/actions.py @ 240:0c306e76d8c5
ipv6 fetch support. refactor Actions to new class and file
Ignore-this: 200d7093919cf001706ad9c02347fabb
author | drewp@bigasterisk.com |
---|---|
date | Mon, 01 Feb 2016 03:28:17 -0800 |
parents | |
children | 3f936fb61e4e |
comparison
equal
deleted
inserted
replaced
239:3f355dd1687c | 240:0c306e76d8c5 |
---|---|
1 from rdflib import URIRef, Namespace, RDF, Literal | |
2 import logging | |
3 import urllib | |
4 | |
5 from cyclone.httpclient import fetch | |
6 log = logging.getLogger('output') | |
7 log.setLevel(logging.WARN) | |
8 | |
9 ROOM = Namespace("http://projects.bigasterisk.com/room/") | |
10 DEV = Namespace("http://projects.bigasterisk.com/device/") | |
11 | |
12 class Actions(object): | |
13 def __init__(self, sendToLiveClients): | |
14 self.sendToLiveClients = sendToLiveClients | |
15 | |
16 def putResults(self, deviceGraph, inferred): | |
17 """ | |
18 some conclusions in the inferred graph lead to PUT requests | |
19 getting made | |
20 | |
21 if the graph contains (?d ?p ?o) and ?d and ?p are a device | |
22 and predicate we support PUTs for, then we look up | |
23 (?d :putUrl ?url) and (?o :putValue ?val) and call | |
24 PUT ?url <- ?val | |
25 | |
26 If the graph doesn't contain any matches, we use (?d | |
27 :zeroValue ?val) for the value and PUT that. | |
28 """ | |
29 | |
30 self._oneShotPostActions(deviceGraph, inferred) | |
31 for dev, pred in [ | |
32 # the config of each putUrl should actually be in the | |
33 # context of a dev and predicate pair, and then that would | |
34 # be the source of this list | |
35 #(DEV.theaterDoorLock, ROOM.state), | |
36 #(URIRef('http://bigasterisk.com/host/bang/monitor'), ROOM.powerState), | |
37 (URIRef('http://bigasterisk.com/host/dash/monitor'), ROOM.powerState), | |
38 (URIRef('http://projects.bigasterisk.com/room/storageCeilingLedLong'), ROOM.brightness), | |
39 (URIRef('http://projects.bigasterisk.com/room/storageCeilingLedCross'), ROOM.brightness), | |
40 ]: | |
41 url = deviceGraph.value(dev, ROOM.putUrl) | |
42 | |
43 if url and dev == DEV.theaterDoorLock: # ew | |
44 self._put(url+"/mode", payload="output") | |
45 | |
46 inferredObjects = list(inferred.objects(dev, pred)) | |
47 if len(inferredObjects) == 0: | |
48 self._putZero(deviceGraph, dev, pred, url) | |
49 elif len(inferredObjects) == 1: | |
50 self._putInferred(deviceGraph, url, inferredObjects[0]) | |
51 elif len(inferredObjects) > 1: | |
52 log.info("conflict, ignoring: %s has %s of %s" % | |
53 (dev, pred, inferredObjects)) | |
54 # write about it to the inferred graph? | |
55 | |
56 #self._frontDoorPuts(deviceGraph, inferred) | |
57 | |
58 | |
59 def _put(self, url, payload): | |
60 def err(e): | |
61 log.warn(" put %s failed (%r)", url, e) | |
62 log.info(" PUT %s payload=%r", url, payload) | |
63 fetch(url, method="PUT", postdata=payload, timeout=2).addErrback(err) | |
64 | |
65 def _oneShotPostActions(self, deviceGraph, inferred): | |
66 """ | |
67 Inferred graph may contain some one-shot statements. We'll send | |
68 statement objects to anyone on web sockets, and also generate | |
69 POST requests as described in the graph. | |
70 | |
71 one-shot statement ?s ?p ?o | |
72 with this in the graph: | |
73 ?osp a :OneShotPost | |
74 ?osp :subject ?s | |
75 ?osp :predicate ?p | |
76 this will cause a post to ?o | |
77 """ | |
78 # nothing in this actually makes them one-shot yet. they'll | |
79 # just fire as often as we get in here, which is not desirable | |
80 log.info("_oneShotPostActions") | |
81 def err(e): | |
82 log.warn("post %s failed", postTarget) | |
83 for osp in deviceGraph.subjects(RDF.type, ROOM['OneShotPost']): | |
84 s = deviceGraph.value(osp, ROOM['subject']) | |
85 p = deviceGraph.value(osp, ROOM['predicate']) | |
86 if s is None or p is None: | |
87 continue | |
88 for postTarget in inferred.objects(s, p): | |
89 log.info("post target %r", postTarget) | |
90 # this packet ought to have 'oneShot' in it somewhere | |
91 self.sendToLiveClients({"s":s, "p":p, "o":postTarget}) | |
92 | |
93 log.info(" POST %s", postTarget) | |
94 fetch(postTarget, method="POST", timeout=2).addErrback(err) | |
95 self._postMpdCommands(inferred) | |
96 | |
97 def _postMpdCommands(self, inferred): | |
98 """special case to be eliminated. mpd play urls are made of an | |
99 mpd service and a song/album/playlist uri to be played. | |
100 Ideally the graph rules would assemble these like | |
101 http://{mpd}/addAndPlay?uri={toPlay} or maybe toPlay as the payload | |
102 which would be fairly general but still allow toPlay uris to | |
103 be matched with any player.""" | |
104 def post(postTarget): | |
105 log.info("special mpd POST %s", postTarget) | |
106 def err(e): | |
107 log.warn("post %s failed", postTarget) | |
108 fetch(postTarget, method="POST", timeout=2).addErrback(err) | |
109 | |
110 rootSkippingAuth = "http://brace:9009/" | |
111 for mpd in [URIRef("http://bigasterisk.com/host/brace/mpd")]: | |
112 | |
113 | |
114 for song in inferred.objects(mpd, ROOM['startMusic']): | |
115 log.info("mpd statement: %r" % song) | |
116 assert song.startswith('http://bigasterisk.com/music/') | |
117 post(rootSkippingAuth + "addAndPlay" + urllib.quote(song[len("http://bigasterisk.com/music"):])) | |
118 | |
119 for state in inferred.objects(mpd, ROOM['playState']): | |
120 log.info('hello playstate %s', state) | |
121 if state == ROOM['pause']: | |
122 log.info("mpd %s %s", mpd, state) | |
123 post(rootSkippingAuth + "mpd/pause") | |
124 for vol in inferred.objects(mpd, ROOM['audioState']): | |
125 if vol == ROOM['volumeStepUp']: | |
126 post(rootSkippingAuth + "volumeAdjust?amount=6&max=70") | |
127 if vol == ROOM['volumeStepDown']: | |
128 post(rootSkippingAuth + "volumeAdjust?amount=-6&min=10") | |
129 | |
130 def _putZero(self, deviceGraph, dev, pred, putUrl): | |
131 # zerovalue should be a function of pred as well. | |
132 value = deviceGraph.value(dev, ROOM.zeroValue) | |
133 if value is not None: | |
134 log.info("put zero (%r) to %s", value, putUrl) | |
135 self._put(putUrl, payload=str(value)) | |
136 # this should be written back into the inferred graph | |
137 # for feedback | |
138 | |
139 def _putInferred(self, deviceGraph, putUrl, obj): | |
140 """ | |
141 HTTP PUT to putUrl, with a payload that's either obj's :putValue | |
142 or obj itself. | |
143 """ | |
144 value = deviceGraph.value(obj, ROOM.putValue) | |
145 if value is not None: | |
146 log.info("put %s to %s", value, putUrl) | |
147 self._put(putUrl, payload=str(value)) | |
148 elif isinstance(obj, Literal): | |
149 log.info("put %s to %s", obj, putUrl) | |
150 self._put(putUrl, payload=str(obj)) | |
151 else: | |
152 log.warn("don't know what payload to put for %s. obj=%r", | |
153 putUrl, obj) | |
154 | |
155 def _frontDoorPuts(self, deviceGraph, inferred): | |
156 # todo: shouldn't have to be a special case | |
157 brt = inferred.value(DEV.frontDoorLcd, ROOM.brightness) | |
158 if brt is None: | |
159 return | |
160 url = deviceGraph.value(DEV.frontDoorLcdBrightness, ROOM.putUrl) | |
161 log.info("put lcd %s brightness %s", url, brt) | |
162 self._put(str(url) + "?brightness=%s" % str(brt), payload='') | |
163 | |
164 msg = "open %s motion %s" % ( | |
165 inferred.value(DEV['frontDoorOpenIndicator'], ROOM.text), | |
166 inferred.value(DEV['frontDoorMotionIndicator'], ROOM.text)) | |
167 # this was meant to be 2 chars in the bottom row, but the | |
168 # easier test was to replace the whole top msg | |
169 #restkit.Resource("http://slash:9080/").put("lcd", message=msg) | |
170 | |
171 |