Python: add asDateTime to Variant
[smartapi.git] / Examples / Python / AdaptDataService / AdaptDataService.py
1 #!/usr/bin/python
2
3 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
4 from io import BytesIO
5 from threading import Thread
6 from httpclient import HttpClient
7 import time
8 import datetime
9 import traceback
10 import random
11
12 from SmartAPI.agents.RegistrationAgent import RegistrationAgent
13 from SmartAPI.agents.SearchAgent import SearchAgent
14
15 from SmartAPI.common.Tools import Tools
16 from SmartAPI.common.RESOURCE import RESOURCE
17
18 from SmartAPI.factory.ResponseFactory import ResponseFactory
19 from SmartAPI.factory.NotificationFactory import NotificationFactory
20
21 from SmartAPI.model.Activity import Activity
22 from SmartAPI.model.Authorization import Authorization
23 from SmartAPI.model.Condition import Condition
24 from SmartAPI.model.Entity import Entity
25 from SmartAPI.model.InterfaceAddress import InterfaceAddress
26 from SmartAPI.model.Offering import Offering
27 from SmartAPI.model.Organization import Organization
28 from SmartAPI.model.PropertyDependentPriceSpecification import PropertyDependentPriceSpecification
29 from SmartAPI.model.Service import Service
30 from SmartAPI.model.TimeSeries import TimeSeries
31 from SmartAPI.model.ValueObject import ValueObject
32
33
34 myIdentity = "http://adapt.asema.com/demos/python/datasource/"
35 myDeviceIdentity = myIdentity + "devices/Cdemodevice"
36 adaptServiceIdentity = "http://adapt.asema.com"
37 registrationServerUri = "http://find.smart-api.io/smart/v1.0e1.0/access"
38 registrationServerKeyUri = "http://find.smart-api.io/smart/v1.0e1.0/key"
39 #registrationServerUri = "http://192.168.2.96:8080/smartapifind-core/smart/v1.0e1.0/access"
40 #registrationServerKeyUri = "http://192.168.2.96:8080/smartapifind-core/smart/v1.0e1.0/key"
41
42 PORT = 8111
43 delay_between_sends_in_seconds = 5
44
45
46 class Notifier(Thread):
47         
48         def __init__(self, iface):
49                 Thread.__init__(self)
50                 self.daemon = True
51                 self.iface = iface
52                 self.running = True
53                 
54                 targetPath = iface.getScheme().asString() + "://" + iface.getHost().asString() + ":" + iface.getPort().asString() + iface.getPath().asString()
55                 print "Start sending notifications to", targetPath
56                 self.http_client = HttpClient(targetPath)
57                 
58         def run(self):
59                 while self.running:
60                         self.sendNotification()
61                         time.sleep(delay_between_sends_in_seconds)
62         
63         def stop(self):
64                 self.running = False
65                 
66         def sendNotification(self):
67                 n = NotificationFactory.create(myIdentity)
68                 a = Activity()
69                 a.setMethod(RESOURCE.NOTIFY)
70                 e = Entity(myDeviceIdentity)
71                 
72                 power = ValueObject(myIdentity + "service/Ppower")
73                 power.setQuantity(RESOURCE.POWER)
74                 power.setUnit(RESOURCE.AMPERE)
75                 power.setValue(float(random.randint(100, 700)))
76                 
77                 e.addValueObject(power)
78                 a.addEntity(e)
79                 n.setActivity(a)
80                 
81                 payload, contentType = Tools.serializeNotification(n)
82                 response = self.http_client.send_data(payload, contentType)
83                 print response
84
85
86 class SampleRegistration(object):
87         
88         def __init__(self):
89                 pass
90
91         def run(self):
92                 agent = RegistrationAgent(myIdentity)
93                 agent.setServerAddress(registrationServerUri)
94                 agent.setServerKeyAddress(registrationServerKeyUri)
95                 agent.setDebugMode(True)
96
97                 # registrate
98                 try:
99                         org = Organization()
100                         org.setName("Asema Electronics Ltd")
101                         
102                         sampleService = Service(myIdentity)
103                         sampleService.setName("Asema Adapt demo data service")
104                         sampleService.setDescription("Demo code for a data source that is compatible with Adapt")
105                         sampleService.setCoordinates(latitude=60.180824, longitude=24.832116)
106                         sampleService.setOwner(org)
107         
108                         auth = Authorization()
109                         auth.addMethod(RESOURCE.COOKIE);
110                         auth.addMethod(RESOURCE.HTTPSTANDARD);
111         
112                         iface = InterfaceAddress()
113                         iface.setHost("127.0.0.1")
114                         iface.setPath("/test/")
115                         iface.setPort(PORT)
116                         iface.setScheme("http")
117
118                         read = Activity()
119                         read.setMethod(RESOURCE.READ)
120                         read.setInterface(iface)
121                         read.setAuthorization(auth)
122
123                         dataSource = Entity()
124                         dataSource.setIdentifierUri(myDeviceIdentity)
125                         dataSource.setName("Demo Adapt datasource")
126                         dataSource.addCapability(read)
127                         dataSource.setManagedBy(myIdentity)
128                         dataSource.setServedBy(adaptServiceIdentity)
129                         dataSource.setCoordinates(latitude=60.180824, longitude=24.832116)
130
131                         dataSource.addCapability(read)
132                         
133                         power = ValueObject(myIdentity + "service/Ppower")
134                         power.addType(RESOURCE.READABLE)
135                         power.setQuantity(RESOURCE.POWER)
136                         power.setUnit(RESOURCE.AMPERE)
137                         power.setMaximum(1000.0)
138                         power.setMinimum(0.0)
139                         power.setName("Power reading")
140                         power.setDescription("This is the power reading of the unit.");
141                         
142                         offering = Offering()
143                         priceSpec = PropertyDependentPriceSpecification()
144                         priceSpec.setName("Sample pricing")
145                         priceSpec.addType(RESOURCE.PRICETYPEDISCOUNT)
146                         
147                         c1 = Condition()
148                         c1.addGreater(0)
149                         c1.addAction(10)
150                         priceSpec.addCondition(c1)
151                         
152                         c2 = Condition()
153                         c2.addGreater(10)
154                         c2.addAction(20)
155                         priceSpec.addCondition(c2)
156                         
157                         c3 = Condition()
158                         c3.addGreater(30)
159                         c3.addAction(40)
160                         priceSpec.addCondition(c3)
161                         
162                         c4 = Condition()
163                         c4.addGreater(40)
164                         c4.addAction(55)
165                         priceSpec.addCondition(c4)
166                         
167                         offering.addPriceSpecification(priceSpec)
168                         dataSource.addOffering(offering)
169                         dataSource.addValueObject(power)
170                         
171                         agent.addEntity(sampleService)
172                         agent.addEntity(dataSource);
173
174                         r = agent.registrate()
175                         if r is None or r.hasErrors():
176                                 print "Demo data service registration FAILED"
177                                 return False
178                         return True
179                 
180                 except:
181                         print "Error in registration code:"
182                         traceback.print_exc()
183                         return False
184
185
186 class SampleDataService(BaseHTTPRequestHandler):
187         
188         def __init__(self, request, client_address, server):
189                 BaseHTTPRequestHandler.__init__(self, request, client_address, server)
190                 
191         # HANDLE GET REQUESTS
192         def do_GET(self):
193                 self.send_response(200)
194                 self.end_headers()
195                         
196                 print("GET " + self.path)
197                         
198                 req_path = self.path.rstrip('/')
199                         
200                 if req_path.endswith("/identify"):
201                         self.wfile.write(str.encode(myIdentity))
202                 elif req_path.endswith("/authorize"):
203                         response_activity = Activity()
204                         response = response_activity.toString()
205                         print("GET " + response)
206                         self.wfile.write(str.encode(response))
207                 else:
208                         print("unhandled request received!")
209         
210         # HANDLE POST REQUESTS
211         def do_POST(self):
212                 content_length = int(self.headers['Content-Length'])
213                 body = self.rfile.read(content_length)
214                 self.send_response(200)
215                 self.end_headers()
216                 response_bytes = BytesIO()
217                 
218                 print("POST" + self.path)
219                 print("POST DATA: " + body)
220                 
221                 req_path = self.path.rstrip('/')
222                 
223                 if req_path.endswith("/authorize"):
224                         # Reply with empty activity to authorize
225                         response_activity = Activity()
226                         response_text = response_activity.toString()
227                         print("POST AUTHORIZE" + response_text)
228                         response_bytes.write(response_text)
229                         
230                 elif req_path.endswith("/access"):
231                         request = Tools.parseRequest(body)
232                         
233                         for a in request.getActivities():
234                                 if a.method.asString() == RESOURCE.SUBSCRIBE:
235                                         print "Subscribing to notifications"
236                                         self.handleSubscription(a)
237                                         
238                                 elif a.method.asString() == RESOURCE.READ:
239                                         # Handle timeseries request
240                                         if a.hasTemporalContext():
241                                                 response_bytes.write(self.handleTemporalContext(a, request))
242                                         else:
243                                                 print("unhandled request received!")
244                 
245                 else:
246                         print("unhandled request received!")
247                 
248                 # Write output to client
249                 self.wfile.write(response_bytes.getvalue())
250         
251         def handleSubscription(self, activity):
252                 if activity.hasInterface():
253                         iface = activity.getInterfaces()[0]
254                         print "Will send data to", iface.getHost().asString()
255                         n = Notifier(iface)
256                         #n.run()
257                 
258                 else:
259                         print "Error: cannot subscribe without inteface data"
260         
261         def handleTemporalContext(self, activity, request):
262                 start = activity.temporalContext.start.asDateTime()
263                 end =  activity.temporalContext.end.asDateTime()
264                 print "Timeseries request from ", start, "to", end
265
266                 # For the client to recognize from which activity this result is, the response
267                 # activity will carry the same identifier that was in the request
268                 response = ResponseFactory.create(myIdentity, request)
269                 response_activity = Activity(activity.getIdentifierUri())
270                 
271                 """
272                 The way results are obtained is up to the server. This could
273                 for instance be a result from a database query,
274                 """
275                 time_series = TimeSeries()
276                 while start < end:
277                         value_object = ValueObject()
278                         value_object.setInstant(start)
279                         value_object.setValue(random.randint(100, 400))
280                         
281                         time_series.addListItem(value_object)
282                         start = start + datetime.timedelta(hours=1)
283                         
284                 # Add timeseries to respose activity
285                 response_activity.addTimeSerie(time_series)
286                 response.addActivity(response_activity)
287                 
288                 return Tools.serializeResponse(response)[0]
289
290
291 def main():
292         registrator = SampleRegistration()
293         registrator.run()
294         
295         httpd = HTTPServer(('', PORT), SampleDataService)
296         httpd.serve_forever()
297
298
299 if __name__ == '__main__':
300         main()
301