HAP-python 1.0__tar.gz → 1.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of HAP-python might be problematic. Click here for more details.

Files changed (35) hide show
  1. {HAP-python-1.0 → HAP-python-1.0.6}/HAP_python.egg-info/PKG-INFO +1 -1
  2. {HAP-python-1.0 → HAP-python-1.0.6}/PKG-INFO +1 -1
  3. {HAP-python-1.0 → HAP-python-1.0.6}/README.md +41 -25
  4. HAP-python-1.0.6/pyhap/accessories/Http.py +207 -0
  5. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessory.py +25 -4
  6. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessory_driver.py +16 -1
  7. {HAP-python-1.0 → HAP-python-1.0.6}/setup.py +1 -1
  8. HAP-python-1.0/pyhap/accessories/Http.py +0 -127
  9. {HAP-python-1.0 → HAP-python-1.0.6}/HAP_python.egg-info/SOURCES.txt +0 -0
  10. {HAP-python-1.0 → HAP-python-1.0.6}/HAP_python.egg-info/dependency_links.txt +0 -0
  11. {HAP-python-1.0 → HAP-python-1.0.6}/HAP_python.egg-info/requires.txt +0 -0
  12. {HAP-python-1.0 → HAP-python-1.0.6}/HAP_python.egg-info/top_level.txt +0 -0
  13. {HAP-python-1.0 → HAP-python-1.0.6}/LICENSE +0 -0
  14. {HAP-python-1.0 → HAP-python-1.0.6}/MANIFEST.in +0 -0
  15. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/__init__.py +0 -0
  16. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/AM2302.py +0 -0
  17. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/BMP180.py +0 -0
  18. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/FakeFan.py +0 -0
  19. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/LightBulb.py +0 -0
  20. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/MotionSensor.py +0 -0
  21. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/ShutdownSwitch.py +0 -0
  22. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/TSL2591.py +0 -0
  23. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/TemperatureSensor.py +0 -0
  24. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/accessories/__init__.py +0 -0
  25. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/characteristic.py +0 -0
  26. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/hap_server.py +0 -0
  27. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/hsrp.py +0 -0
  28. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/loader.py +0 -0
  29. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/params.py +0 -0
  30. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/resources/characteristics.json +0 -0
  31. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/resources/services.json +0 -0
  32. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/service.py +0 -0
  33. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/tlv.py +0 -0
  34. {HAP-python-1.0 → HAP-python-1.0.6}/pyhap/util.py +0 -0
  35. {HAP-python-1.0 → HAP-python-1.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: HAP-python
3
- Version: 1.0
3
+ Version: 1.0.6
4
4
  Summary: HomeKit Accessory Protocol implementation in python3
5
5
  Home-page: https://github.com/ikalchev/HAP-python.git
6
6
  Author: Ivan Kalchev
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: HAP-python
3
- Version: 1.0
3
+ Version: 1.0.6
4
4
  Summary: HomeKit Accessory Protocol implementation in python3
5
5
  Home-page: https://github.com/ikalchev/HAP-python.git
6
6
  Author: Ivan Kalchev
@@ -1,3 +1,4 @@
1
+ [![PyPI version](https://badge.fury.io/py/HAP-python.svg)](https://badge.fury.io/py/HAP-python)
1
2
  # HAP-python
2
3
 
3
4
  HomeKit Accessory Protocol implementation in python 3 (tested with 3.4, 3.5 and 3.6).
@@ -28,23 +29,12 @@ On a Raspberry Pi, you can get it with:
28
29
  ```
29
30
  sudo apt-get install libavahi-compat-libdnssd-dev
30
31
  ```
31
- `avahi-utils` may also fit the bill. Then, to install HAP-python, you will need `setuptools` or `pip3`.
32
- Just git clone this project and install it like (you will need `sudo` or `--user` for the install):
33
-
32
+ `avahi-utils` may also fit the bill. Then, you can install with `pip3` (you will need `sudo` or `--user` for the install):
34
33
  ```sh
35
- git clone https://github.com/ikalchev/HAP-python.git && cd HAP-python
36
- python3 setup.py install
37
- ```
38
- or
39
- ```
40
- pip3 install .
34
+ pip3 install HAP-python
41
35
  ```
42
36
 
43
- This will install HAP-python in your python packages, so that you can import it as `pyhap`.
44
- Alternatively, you can install only the dependencies and run with the root directory of this project in your `PYTHONPATH`.
45
-
46
- To uninstall, just do:
47
-
37
+ This will install HAP-python in your python packages, so that you can import it as `pyhap`. To uninstall, just do:
48
38
  ```
49
39
  pip3 uninstall HAP-python
50
40
  ```
@@ -125,30 +115,56 @@ class TemperatureSensor(Accessory):
125
115
 
126
116
  ## Integrating non-compatible devices <a name="HttpAcc"></a>
127
117
  HAP-python may not be available for many IoT devices. For them, HAP-python allows devices
128
- to be bridged by means of communicating with an HTTP server - the [Http Accessory](pyhap/accessories/Http.py).
118
+ to be bridged by means of communicating with an HTTP server - the [HttpBridge](pyhap/accessories/Http.py). You can add as many remote accessories as you like.
129
119
 
130
120
  For example, the bellow snippet creates an Http Accessory that listens on port 51800
131
121
  for updates on the TemperatureSensor service:
132
122
  ```python
133
123
  import pyhap.util as util
134
- from pyhap.accessories.Http import Http
135
- from pyhap.accessory import STANDALONE_AID
124
+ import pyhap.loader as loader
125
+ from pyhap.accessories.Http import HttpBridge
126
+ from pyhap.accessory import Accessory
136
127
  from pyhap.accessory_driver import AccessoryDriver
137
128
 
138
- http = Http(("", 51800), ["TemperatureSensor"], "HTTP bridge",
139
- aid=STANDALONE_AID, mac=util.generate_mac(), pincode=b"203-23-999")
140
- driver = AccessoryDriver(http, 51826)
129
+ # get loaders
130
+ service_loader = loader.get_serv_loader()
131
+ char_loader = loader.get_char_loader()
132
+
133
+ # Create an accessory with the temperature sensor service.
134
+ # Also, add an optional characteristic StatusLowBattery to that service.
135
+ remote_accessory = Accessory("foo", aid=2) # aids must be unique for each accessory.
136
+ tservice = service_loader.get("TemperatureSensor")
137
+ tservice.add_opt_characteristic(
138
+ char_loader.get("StatusLowBattery"))
139
+ remote_accessory.add_service(tservice)
140
+
141
+ # Create the HTTP Bridge and add the accessory to it.
142
+ address = ("", 51111)
143
+ http_bridge = HttpBridge(address=address,
144
+ display_name="HTTP Bridge",
145
+ pincode=b"203-23-999")
146
+ http_bridge.add_accessory(remote_accessory)
147
+
148
+ # Add to driver and run.
149
+ driver = AccessoryDriver(http_bridge, 51826)
141
150
  driver.start()
142
151
  ```
143
152
  Now, remote accessories can do an HTTP POST to the address of the device where the
144
- accessory is running (port 51800) with the following content:
153
+ accessory is running (port 51111) with the following content:
145
154
  ```json
146
- { "TemperatureSensor" : {
147
- "CurrentTemperature" : 20 }
155
+ {
156
+ "aid": 2,
157
+ "services": {
158
+ "TemperatureSensor": {
159
+ "CurrentTemperature" : 20,
160
+ "StatusLowBattery": true,
161
+ }
162
+ }
148
163
  }
149
164
  ```
150
- This will update the value of the characteristic "CurrentTemperature" to 20 degrees C.
151
- Needless to say the communication to the Http Accessory poses a security risk, so
165
+ This will update the value of the characteristic "CurrentTemperature" to 20 degrees C
166
+ and "StatusLowBattery" to `true`.
167
+ Needless to say the communication to the Http Bridge poses a security risk, so
152
168
  keep that in mind.
153
169
 
154
170
  ## Run at boot <a name="AtBoot"></a>
@@ -0,0 +1,207 @@
1
+ """This module provides HttpAccessory - an accessory that
2
+ allows remote devices to provide HAP services by sending POST
3
+ requests.
4
+ """
5
+ import json
6
+ import threading
7
+ import logging
8
+ from http.server import HTTPServer, BaseHTTPRequestHandler
9
+
10
+ from pyhap.accessory import Bridge, Category
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class HttpBridgeHandler(BaseHTTPRequestHandler):
16
+ """Handles requests and passes value updates to an HttpAccessory.
17
+
18
+ The POST request should contain json data with the format:
19
+ { "aid": <aid>
20
+ "services": {
21
+ <service>: {
22
+ <characteristic>: value,
23
+ }
24
+ }
25
+ }
26
+
27
+ Example:
28
+ { "aid": 2
29
+ "services": {
30
+ TemperatureSensor" : {
31
+ "CurrentTemperature": 20
32
+ }
33
+ }
34
+ }
35
+ """
36
+
37
+ def __init__(self, http_accessory, sock, client_addr, server):
38
+ """Create a handler that passes updates to the given HttpAccessory.
39
+ """
40
+ self.http_accessory = http_accessory
41
+ super(HttpBridgeHandler, self).__init__(sock, client_addr, server)
42
+
43
+ def respond_ok(self):
44
+ """Reply with code 200 (OK) and close the connection.
45
+ """
46
+ self.send_response(200)
47
+ self.send_header("Content-Type", "text/html")
48
+ self.send_header("Content-Length", 0)
49
+ self.end_headers()
50
+ self.close_connection = 1
51
+
52
+ def respond_err(self):
53
+ """Reply with code 400 and close the connection.
54
+ """
55
+ self.send_response(400)
56
+ self.send_header("Content-Type", "text/html")
57
+ self.send_header("Content-Length", 0)
58
+ self.end_headers()
59
+ self.close_connection = 1
60
+
61
+ def do_POST(self):
62
+ """Read the payload as json and update the state of the accessory.
63
+ """
64
+ length = int(self.headers["Content-Length"])
65
+ try:
66
+ # The below decode is necessary only for python <3.6, because loads prior 3.6
67
+ # doesn't know bytes/bytearray.
68
+ content = self.rfile.read(length).decode("utf-8")
69
+ data = json.loads(content)
70
+ except Exception as e:
71
+ logger.error("Bad POST request; Error was: %s", str(e))
72
+ self.respond_err()
73
+ else:
74
+ self.http_accessory.update_state(data)
75
+ self.respond_ok()
76
+
77
+
78
+ class HttpBridge(Bridge):
79
+ """An accessory that listens to HTTP requests containing characteristic updates.
80
+
81
+ Simple devices/implementations can just HTTP POST data as:
82
+
83
+ {
84
+ <aid>: int,
85
+ "services": {
86
+ <service1>: {
87
+ <characteristic1>: value
88
+ ...
89
+ }
90
+ ...
91
+ }
92
+ }
93
+
94
+ Then this accessory takes care of communicating this update to any HAP clients.
95
+
96
+ The way you configure a HttpBridge is by adding Accessory objects. In the
97
+ example below, we add three accessories to a HTTP Bridge:
98
+ >>> # get loaders
99
+ >>> service_loader = loader.get_serv_loader()
100
+ >>> char_loader = loader.get_char_loader()
101
+ >>>
102
+ >>> # Create an accessory with the temperature sensor service.
103
+ >>> temperature_acc_1 = Accessory("temp1", 2)
104
+ >>> temperature_acc_1.add_service(service_loader.get("TemperatureSensor"))
105
+ >>>
106
+ >>> # Create an accessory with the temperature sensor service.
107
+ >>> # Also, add an optional characteristic Name to the service.
108
+ >>> temperature_acc_2 = Accessory("temp2", 3)
109
+ >>> temp_service = service_loader.get("TemperatureSensor")
110
+ >>> temp_service.add_opt_characteristic(char_loader.get("StatusLowBattery"))
111
+ >>> temperature_acc_2.add_service(temp_service)
112
+ >>>
113
+ >>> # Create a lightbulb accessory.
114
+ >>> light_bulb_acc = Accessory("bulb", 4)
115
+ >>> light_bulb_acc.add_service(service_loader.get("Lightbulb"))
116
+ >>>
117
+ >>> # Finally, create the HTTP Bridge and add all accessories to it.
118
+ >>> http_bridge = HttpBridge("HTTP Bridge", address=("", 51111))
119
+ >>> for accessory in (temperature_acc_1, temperature_acc_2, light_bulb_acc):
120
+ ... http_bridge.add_accessory(accessory)
121
+ >>>
122
+ >>> # add to an accessory driver and start as usual
123
+ """
124
+
125
+ category = Category.OTHER
126
+
127
+ def __init__(self, address, *args, **kwargs):
128
+ """Initialise and add the given services.
129
+
130
+ @param address: The address-port on which to listen for requests.
131
+ @type address: tuple(str, int)
132
+
133
+ @param accessories:
134
+ """
135
+ super(HttpBridge, self).__init__(*args, **kwargs)
136
+
137
+ # For exclusive access to updates. Slight overkill...
138
+ self.update_lock = None
139
+ self.server_thread = None
140
+ self._set_server(address)
141
+
142
+ def _set_server(self, address):
143
+ """Set up a HTTPServer to listen on the given address.
144
+ """
145
+ self.server = HTTPServer(address, lambda *a: HttpBridgeHandler(self, *a))
146
+ self.server_thread = threading.Thread(target=self.server.serve_forever)
147
+ self.update_lock = threading.Lock()
148
+
149
+ def __getstate__(self):
150
+ """Return the state of this instance, less the server and server thread.
151
+
152
+ Also add the server address. All this is because we cannot pickle such
153
+ objects and to allow to recover the server using the address.
154
+ """
155
+ state = super(HttpBridge, self).__getstate__()
156
+ state["server"] = None
157
+ state["server_thread"] = None
158
+ state["update_lock"] = None
159
+ state["address"] = self.server.server_address
160
+ return state
161
+
162
+ def __setstate__(self, state):
163
+ """Load the state and set up the server with the address in the state.
164
+ """
165
+ self.__dict__.update(state)
166
+ self._set_server(state["address"])
167
+
168
+ def update_state(self, data):
169
+ """Update the characteristics from the received data.
170
+
171
+ Expected to be called from HapHttpHandler. Updates are thread-safe.
172
+
173
+ @param data: A dict of values that should be set, e.g.:
174
+ {
175
+ <aid>: int,
176
+ <service1 name> : {
177
+ <characteristic1 name>: value
178
+ ...
179
+ }
180
+ ...
181
+ }
182
+ @type data: dict
183
+ """
184
+ aid = data["aid"]
185
+ logger.debug("Got update from accessory with aid: %d", aid)
186
+ accessory = self.accessories[aid]
187
+ service_data = data["services"]
188
+ for service, char_data in service_data.items():
189
+ service_obj = accessory.get_service(service)
190
+ for char, value in char_data.items():
191
+ char_obj = service_obj.get_characteristic(char)
192
+ with self.update_lock:
193
+ char_obj.set_value(value)
194
+
195
+ def stop(self):
196
+ """Stop the server.
197
+ """
198
+ super(HttpBridge, self).stop()
199
+ logger.debug("Stopping HTTP bridge server.")
200
+ self.server.shutdown()
201
+ self.server.server_close()
202
+
203
+ def run(self):
204
+ """Start the server - can listen for requests.
205
+ """
206
+ logger.debug("Starting HTTP bridge server.")
207
+ self.server_thread.start()
@@ -112,7 +112,8 @@ class Accessory(object):
112
112
  mac = util.generate_mac()
113
113
  return cls(display_name, aid=aid, mac=mac, pincode=pincode)
114
114
 
115
- def __init__(self, display_name, aid=None, mac=None, pincode=None, iid_manager=None):
115
+ def __init__(self, display_name, aid=STANDALONE_AID, mac=None, pincode=None,
116
+ iid_manager=None):
116
117
 
117
118
  self.display_name = display_name
118
119
  self.aid = aid
@@ -145,7 +146,6 @@ class Accessory(object):
145
146
  The default implementation adds only the AccessoryInformation services
146
147
  and sets its Name characteristic to the Accessory's display name.
147
148
  """
148
- # Info service
149
149
  info_service = get_serv_loader().get("AccessoryInformation")
150
150
  info_service.get_characteristic("Name")\
151
151
  .set_value(self.display_name, False)
@@ -171,6 +171,22 @@ class Accessory(object):
171
171
  """
172
172
  self.run_sentinel = run_sentinel
173
173
 
174
+ def config_changed(self):
175
+ """Notify the accessory about configuration changes.
176
+
177
+ These include new services or updated characteristic values, e.g.
178
+ the Name of a service changed.
179
+
180
+ This method also notifies the broker about the change, so that it can
181
+ publish the changes to the world.
182
+
183
+ @note: If you are changing the configuration of a bridged accessory
184
+ (i.e. an Accessory that is contained in a Bridge),
185
+ you should call the `config_changed` method on the Bridge.
186
+ """
187
+ self.config_version += 1
188
+ self.broker.config_changed()
189
+
174
190
  def add_service(self, *servs):
175
191
  """Add the given services to this Accessory.
176
192
 
@@ -298,8 +314,13 @@ class Bridge(Accessory):
298
314
 
299
315
  category = Category.BRIDGE
300
316
 
301
- def __init__(self, display_name, **kwargs):
302
- super(Bridge, self).__init__(display_name, aid=STANDALONE_AID, **kwargs)
317
+ def __init__(self, display_name, mac=None, pincode=None, iid_manager=None):
318
+ aid = STANDALONE_AID
319
+ # A Bridge cannot be Bridge, hence talks directly to HAP clients.
320
+ # Thus, we need a mac.
321
+ mac = mac or util.generate_mac()
322
+ super(Bridge, self).__init__(display_name, aid=aid, mac=mac,
323
+ pincode=pincode, iid_manager=iid_manager)
303
324
  self.accessories = {} # aid: acc
304
325
 
305
326
  def _set_services(self):
@@ -12,7 +12,8 @@ AccessoryDriver (all this happens through the publish() interface). The Accessor
12
12
  will then check if there is a client that subscribed for events from this exact
13
13
  Characteristic from this exact Accessory (remember, it could be a Bridge with more than
14
14
  one Accessory in it). If so, the event is put in a FIFO queue - the event queue. This
15
- terminates the call chain and concludes the publishing process from the Characteristic.
15
+ terminates the call chain and concludes the publishing process from the Characteristic,
16
+ the Characteristic does not block waiting for the actual send to happen.
16
17
 
17
18
  When the AccessoryDriver is started, it spawns an event dispatch thread. The purpose of
18
19
  this thread is to get events from the event queue and send them to subscribed clients.
@@ -217,6 +218,16 @@ class AccessoryDriver(object):
217
218
  self.sent_events = 0
218
219
  self.accumulated_qsize = 0
219
220
 
221
+ def config_changed(self):
222
+ """Notify the driver that the accessory's configuration has changed.
223
+
224
+ Updates the mDNS advertisment, so that iOS clients know they need to new data.
225
+ Also, persists the accessory, so that the new configuration is available on
226
+ restart.
227
+ """
228
+ self.update_advertisment()
229
+ self.persist()
230
+
220
231
  def update_advertisment(self):
221
232
  """Updates the mDNS service info for the accessory."""
222
233
  self.advertiser.unregister_service(self.mdns_service_info)
@@ -434,6 +445,10 @@ class AccessoryDriver(object):
434
445
  self.http_server.shutdown()
435
446
  self.http_server.server_close()
436
447
  self.http_server_thread.join()
448
+
449
+ logger.debug("Persisting accessory state")
450
+ self.persist()
451
+
437
452
  logger.debug("AccessoryDriver stopped successfully")
438
453
 
439
454
  def signal_handler(self, _signal, _frame):
@@ -4,7 +4,7 @@ setup(
4
4
  name="HAP-python",
5
5
  description="HomeKit Accessory Protocol implementation in python3",
6
6
  author="Ivan Kalchev",
7
- version="1.0",
7
+ version="1.0.6",
8
8
  url="https://github.com/ikalchev/HAP-python.git",
9
9
  classifiers=[
10
10
  "Development Status :: 5 - Production/Stable",
@@ -1,127 +0,0 @@
1
- """An accessory that listens to HTTP requests containing characteristic updates.
2
-
3
- A more simple device/implementation can just HTTP POST data as:
4
- { <service_name>: {
5
- <characteristic_name>: value
6
- }
7
- }
8
- Then this accessory takes care of communicating this update to any HAP clients.
9
- """
10
- import json
11
- import threading
12
- import logging
13
- from http.server import HTTPServer, BaseHTTPRequestHandler
14
-
15
- from pyhap.accessory import Accessory, Category
16
- import pyhap.loader as loader
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
-
21
- class HapHttpHandler(BaseHTTPRequestHandler):
22
- """
23
- Handles POST requests and passes characteristic value updates to an HttpAccessory.
24
-
25
- The POST request should contain json data with the format:
26
- { <service_name>: {
27
- <characteristic_name>: value,
28
- }
29
- }
30
-
31
- Example:
32
- { "TemperatureSensor" : {
33
- "CurrentTemperature": 20
34
- }
35
- }
36
- """
37
-
38
- def __init__(self, httpAccessory, sock, client_addr, server):
39
- """
40
- Creates a handler that passes updates to the given HttpAccessory.
41
- """
42
- self.httpAccessory = httpAccessory
43
- super(HapHttpHandler, self).__init__(sock, client_addr, server)
44
-
45
- def respond_ok(self):
46
- self.send_response(200)
47
- self.send_header("Content-Type", "text/html")
48
- self.send_header("Content-Length", 0)
49
- self.end_headers()
50
- self.close_connection = 1
51
-
52
- def respond_err(self):
53
- self.send_response(400)
54
- self.send_header("Content-Type", "text/html")
55
- self.send_header("Content-Length", 0)
56
- self.end_headers()
57
- self.close_connection = 1
58
-
59
- def do_POST(self):
60
- """
61
- Read the payload as json and update the state of the httpAccessory.
62
- """
63
- length = int(self.headers["Content-Length"])
64
- try:
65
- # The below decode is necessary only for python <3.6, because loads prior 3.6
66
- # doesn't know bytes/bytearray.
67
- content = self.rfile.read(length).decode("utf-8")
68
- data = json.loads(content)
69
- except Exception as e:
70
- logger.error("Bad POST request; Error was: %s", str(e))
71
- self.respond_err()
72
- else:
73
- self.httpAccessory.update_state(data)
74
- self.respond_ok()
75
-
76
-
77
- '''TODO: should make it possible to init with {"aid" : [services]}
78
- or {"addr": [services]} etc., so that this accessory can bridge several
79
- other. In this way remote devices can use a simple interface and this module will do
80
- the hap magic.
81
- '''
82
-
83
-
84
- class Http(Accessory):
85
-
86
- category = Category.OTHER
87
-
88
- def __init__(self, address, hapServices, *args, **kwargs):
89
- self.hapServices = hapServices
90
- super(Http, self).__init__(*args, **kwargs)
91
- self._set_server(address)
92
-
93
- def _set_server(self, address):
94
- self.server = HTTPServer(address, lambda *a: HapHttpHandler(self, *a))
95
- self.serverThread = threading.Thread(target=self.server.serve_forever)
96
-
97
- def _set_services(self):
98
- super(Http, self)._set_services()
99
- ldr = loader.get_serv_loader()
100
- for s in self.hapServices:
101
- self.add_service(ldr.get(s))
102
-
103
- def __getstate__(self):
104
- state = super(Http, self).__getstate__()
105
- state["server"] = None
106
- state["serverThread"] = None
107
- state["address"] = self.server.server_address
108
- return state
109
-
110
- def __setstate__(self, state):
111
- self.__dict__.update(state)
112
- self._set_server(state["address"])
113
-
114
- def update_state(self, data):
115
- for service, charData in data.items():
116
- serviceObj = self.get_service(service)
117
- for char, value in charData.items():
118
- charObj = serviceObj.get_characteristic(char)
119
- charObj.set_value(value)
120
-
121
- def stop(self):
122
- super(Http, self).stop()
123
- self.server.shutdown()
124
- self.server.server_close()
125
-
126
- def run(self):
127
- self.serverThread.start()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes