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