comparison service/reasoning/actions.py @ 1197:d8acab2b01f5

mqtt has two devices now. various older cleanups. Ignore-this: 67ca3acc5dc6aa672d0c896c9f5ae48e darcs-hash:964511475873219e6bc4725388a8d2e54a3c4e28
author drewp <drewp@bigasterisk.com>
date Sat, 19 Jan 2019 12:08:59 -0800
parents 114ca7fd9d01
children 1ceb26846eca
comparison
equal deleted inserted replaced
1196:ef15d8915d09 1197:d8acab2b01f5
24 PUT ?url <- ?val 24 PUT ?url <- ?val
25 25
26 If the graph doesn't contain any matches, we use (?d 26 If the graph doesn't contain any matches, we use (?d
27 :zeroValue ?val) for the value and PUT that. 27 :zeroValue ?val) for the value and PUT that.
28 """ 28 """
29 29 self._putDevices(deviceGraph, inferred)
30 self._oneShotPostActions(deviceGraph, inferred) 30 self._oneShotPostActions(deviceGraph, inferred)
31 for dev, pred in [ 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), 32 #(URIRef('http://bigasterisk.com/host/bang/monitor'), ROOM.powerState),
37 (URIRef('http://bigasterisk.com/host/dash/monitor'), ROOM.powerState), 33 (URIRef('http://bigasterisk.com/host/dash/monitor'), ROOM.powerState),
34 (URIRef('http://bigasterisk.com/host/frontdoor/monitor'), ROOM.powerState),
38 (ROOM['storageCeilingLedLong'], ROOM.brightness), 35 (ROOM['storageCeilingLedLong'], ROOM.brightness),
39 (ROOM['storageCeilingLedCross'], ROOM.brightness), 36 (ROOM['storageCeilingLedCross'], ROOM.brightness),
37 (ROOM['garageOverhead'], ROOM.brightness),
40 (ROOM['headboardWhite'], ROOM.brightness), 38 (ROOM['headboardWhite'], ROOM.brightness),
41 (ROOM['changingWhite'], ROOM.brightness), 39 (ROOM['changingWhite'], ROOM.brightness),
42 (ROOM['starTrekLight'], ROOM.brightness), 40 (ROOM['starTrekLight'], ROOM.brightness),
41 (ROOM['kitchenLight'], ROOM.brightness),
42 (ROOM['kitchenCounterLight'], ROOM.brightness),
43 (ROOM['livingRoomLamp1'], ROOM.brightness), 43 (ROOM['livingRoomLamp1'], ROOM.brightness),
44 (ROOM['livingRoomLamp2'], ROOM.brightness), 44 (ROOM['livingRoomLamp2'], ROOM.brightness),
45 (ROOM['bedLedStrip'], ROOM.color), 45 (ROOM['bedLedStrip'], ROOM.color),
46 ]: 46 ]:
47 url = deviceGraph.value(dev, ROOM.putUrl) 47 url = deviceGraph.value(dev, ROOM.putUrl)
48 48
49 if url and dev == DEV.theaterDoorLock: # ew 49 log.debug('inferredObjects of dev=%s pred=%s',
50 self._put(url+"/mode", payload="output") 50 deviceGraph.qname(dev),
51 51 deviceGraph.qname(pred))
52 inferredObjects = list(inferred.objects(dev, pred)) 52 inferredObjects = list(inferred.objects(dev, pred))
53 if len(inferredObjects) == 0: 53 if len(inferredObjects) == 0:
54 self._putZero(deviceGraph, dev, pred, url) 54 self._putZero(deviceGraph, dev, pred, url)
55 elif len(inferredObjects) == 1: 55 elif len(inferredObjects) == 1:
56 log.debug('inferredObject: %s %s %r', 56 log.debug(' inferredObject: %s %s %r',
57 deviceGraph.qname(dev), 57 deviceGraph.qname(dev),
58 deviceGraph.qname(pred), 58 deviceGraph.qname(pred),
59 inferredObjects[0]) 59 inferredObjects[0].toPython())
60 self._putInferred(deviceGraph, url, inferredObjects[0]) 60 self._putInferred(deviceGraph, url, inferredObjects[0])
61 elif len(inferredObjects) > 1: 61 elif len(inferredObjects) > 1:
62 log.info("conflict, ignoring: %s has %s of %s" % 62 log.info(" conflict, ignoring: %s has %s of %s" %
63 (dev, pred, inferredObjects)) 63 (dev, pred, inferredObjects))
64 # write about it to the inferred graph? 64 # write about it to the inferred graph?
65 65
66 #self._frontDoorPuts(deviceGraph, inferred)
67
68 def _oneShotPostActions(self, deviceGraph, inferred): 66 def _oneShotPostActions(self, deviceGraph, inferred):
69 """ 67 """
70 Inferred graph may contain some one-shot statements. We'll send 68 Inferred graph may contain some one-shot statements. We'll send
71 statement objects to anyone on web sockets, and also generate 69 statement objects to anyone on web sockets, and also generate
72 POST requests as described in the graph. 70 POST requests as described in the graph.
86 for osp in deviceGraph.subjects(RDF.type, ROOM['OneShotPost']): 84 for osp in deviceGraph.subjects(RDF.type, ROOM['OneShotPost']):
87 s = deviceGraph.value(osp, ROOM['subject']) 85 s = deviceGraph.value(osp, ROOM['subject'])
88 p = deviceGraph.value(osp, ROOM['predicate']) 86 p = deviceGraph.value(osp, ROOM['predicate'])
89 if s is None or p is None: 87 if s is None or p is None:
90 continue 88 continue
91 log.info("checking for %s %s", s, p) 89 #log.info("checking for %s %s", s, p)
92 for postTarget in inferred.objects(s, p): 90 for postTarget in inferred.objects(s, p):
93 log.info("post target %r", postTarget) 91 log.info("post target %r", postTarget)
94 # this packet ought to have 'oneShot' in it somewhere 92 # this packet ought to have 'oneShot' in it somewhere
95 self.sendToLiveClients({"s":s, "p":p, "o":postTarget}) 93 self.sendToLiveClients({"s":s, "p":p, "o":postTarget})
96 94
97 log.info(" POST %s", postTarget) 95 log.info(" POST %s", postTarget)
98 fetch(postTarget, method="POST", timeout=2).addErrback(err) 96 fetch(postTarget, method="POST", timeout=2).addErrback(err)
99 self._postMpdCommands(inferred)
100
101 def _postMpdCommands(self, inferred):
102 """special case to be eliminated. mpd play urls are made of an
103 mpd service and a song/album/playlist uri to be played.
104 Ideally the graph rules would assemble these like
105 http://{mpd}/addAndPlay?uri={toPlay} or maybe toPlay as the payload
106 which would be fairly general but still allow toPlay uris to
107 be matched with any player."""
108 97
109 rootSkippingAuth = "http://brace:9009/" 98 def _putDevices(self, deviceGraph, inferred):
110 for mpd in [URIRef("http://bigasterisk.com/host/brace/mpd")]: 99 agentFor = {}
111 100 for stmt in inferred:
112 for song in inferred.objects(mpd, ROOM['startMusic']): 101 if stmt[1] == ROOM['putAgent']:
113 log.info("mpd statement: %r" % song) 102 agentFor[stmt[0]] = stmt[2]
114 assert song.startswith('http://bigasterisk.com/music/') 103 for stmt in inferred:
115 self.post(rootSkippingAuth + "addAndPlay" + urllib.quote(song[len("http://bigasterisk.com/music"):])) 104 putUrl = deviceGraph.value(stmt[0], ROOM['putUrl'])
116 105 putPred = deviceGraph.value(stmt[0], ROOM['putPredicate'])
117 for state in inferred.objects(mpd, ROOM['playState']): 106 if putUrl and putPred == stmt[1]:
118 log.info('hello playstate %s', state) 107 self._put(putUrl + '?' + urllib.urlencode([
119 if state == ROOM['pause']: 108 ('s', str(stmt[0])),
120 log.info("mpd %s %s", mpd, state) 109 ('p', str(stmt[1]))]),
121 self.post(rootSkippingAuth + "mpd/pause") 110 str(stmt[2].toPython()),
122 for vol in inferred.objects(mpd, ROOM['audioState']): 111 agent=agentFor.get(stmt[0], None))
123 if vol == ROOM['volumeStepUp']:
124 self.post(rootSkippingAuth + "volumeAdjust?amount=6&max=70")
125 if vol == ROOM['volumeStepDown']:
126 self.post(rootSkippingAuth + "volumeAdjust?amount=-6&min=10")
127
128 def _frontDoorPuts(self, deviceGraph, inferred):
129 # todo: shouldn't have to be a special case
130 brt = inferred.value(DEV.frontDoorLcd, ROOM.brightness)
131 if brt is None:
132 return
133 url = deviceGraph.value(DEV.frontDoorLcdBrightness, ROOM.putUrl)
134 log.info("put lcd %s brightness %s", url, brt)
135 self._put(str(url) + "?brightness=%s" % str(brt), payload='')
136
137 msg = "open %s motion %s" % (
138 inferred.value(DEV['frontDoorOpenIndicator'], ROOM.text),
139 inferred.value(DEV['frontDoorMotionIndicator'], ROOM.text))
140 # this was meant to be 2 chars in the bottom row, but the
141 # easier test was to replace the whole top msg
142 #restkit.Resource("http://slash:9080/").put("lcd", message=msg)
143
144
145
146
147 def _put(self, url, payload):
148 def err(e):
149 log.warn(" put %s failed (%r)", url, e)
150 log.info(" PUT %s payload=%r", url, payload)
151 fetch(url, method="PUT", postdata=payload, timeout=2).addErrback(err)
152
153 def post(self, postTarget):
154 log.info("special mpd POST %s", postTarget)
155 def err(e):
156 log.warn("post %s failed", postTarget)
157 fetch(postTarget, method="POST", timeout=2).addErrback(err)
158
159 def _putZero(self, deviceGraph, dev, pred, putUrl):
160 # zerovalue should be a function of pred as well.
161 value = deviceGraph.value(dev, ROOM.zeroValue)
162 if value is not None:
163 log.info("put zero (%r) to %s", value, putUrl)
164 self._put(putUrl, payload=str(value))
165 # this should be written back into the inferred graph
166 # for feedback
167 112
168 def _putInferred(self, deviceGraph, putUrl, obj): 113 def _putInferred(self, deviceGraph, putUrl, obj):
169 """ 114 """
170 HTTP PUT to putUrl, with a payload that's either obj's :putValue 115 HTTP PUT to putUrl, with a payload that's either obj's :putValue
171 or obj itself. 116 or obj itself.
174 if value is not None: 119 if value is not None:
175 self._put(putUrl, payload=str(value)) 120 self._put(putUrl, payload=str(value))
176 elif isinstance(obj, Literal): 121 elif isinstance(obj, Literal):
177 self._put(putUrl, payload=str(obj)) 122 self._put(putUrl, payload=str(obj))
178 else: 123 else:
179 log.warn("don't know what payload to put for %s. obj=%r", 124 log.warn(" don't know what payload to put for %s. obj=%r",
180 putUrl, obj) 125 putUrl, obj)
126
127 def _putZero(self, deviceGraph, dev, pred, putUrl):
128 # zerovalue should be a function of pred as well.
129 value = deviceGraph.value(dev, ROOM.zeroValue)
130 if value is not None:
131 log.info(" put zero (%r) to %s", value.toPython(), putUrl)
132 self._put(putUrl, payload=str(value))
133 # this should be written back into the inferred graph
134 # for feedback
135
136 def _put(self, url, payload, agent=None):
137 assert isinstance(payload, bytes)
138 def err(e):
139 log.warn(" put %s failed (%r)", url, e)
140 log.info(" PUT %s payload=%s agent=%s", url, payload, agent)
141 headers = {}
142 if agent is not None:
143 headers['x-foaf-agent'] = [str(agent)]
144 fetch(url, method="PUT", postdata=payload, timeout=2,
145 headers=headers).addErrback(err)