def make_thing(): thing = Thing('Sense Hat', type_='Sense Hat', description='A Web Thing Enable Raspberry PI Sense Hat') thing.add_property( Property(thing, 'on', Value(True), metadata={ '@type': 'OnOffProperty', 'label': 'On/Off', 'type': 'boolean', 'description': 'Whether the Sense Hat is turned on', })) thing.add_available_action( 'Hello', { 'label': 'Hello', 'description': 'Make the sense hat say hello', 'input': { 'type': 'object', 'required': [ 'text', ], 'properties': { 'text': { 'type': 'string', }, }, }, }, HelloAction) return thing
def make_light(client, observer, light): thing = Thing(light['name'], ['OnOffSwitch', 'Light'], 'A web connected lamp') def update_on(on): client.normal_request(1, light['address'], 1 if on else 0) value = Value(False, update_on) ioloop = tornado.ioloop.IOLoop.instance() def update_handler(what): ioloop.add_callback(lambda : value.notify_of_external_update(what != '0')) observer.add_listener('1', str(light['address']), update_handler) thing.add_property( Property(thing, 'on', value, metadata={ '@type': 'OnOffProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) return thing
def make_thing(): thing = Thing('My Lamp', 'dimmableLight', 'A web connected lamp') def noop(_): pass thing.add_property( Property(thing, 'on', Value(True, noop), metadata={ 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_property( Property(thing, 'level', Value(50, noop), metadata={ 'type': 'number', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, })) thing.add_available_action( 'fade', { 'description': 'Fade the lamp to a given level', 'input': { 'type': 'object', 'required': [ 'level', 'duration', ], 'properties': { 'level': { 'type': 'number', 'minimum': 0, 'maximum': 100, }, 'duration': { 'type': 'number', 'unit': 'milliseconds', }, }, } }, FadeAction) thing.add_available_event( 'overheated', { 'description': 'The lamp has exceeded its safe operating temperature', 'type': 'number', 'unit': 'celsius' }) return thing
def run_server(): sht = SHT20(1, 0x40) h, t = sht.all() celsius = Value(t.C) humidity = Value(h.RH) thing = Thing('urn:dev:ops:humidity-temperature-sensor', 'SHT20_Anthony', ['MultiLevelSensor']) thing.add_property( Property(thing, 'humidity', humidity, metadata={ '@type': 'LevelProperty', 'title': 'Humidity', 'type': 'number', 'unit': 'percent', 'readOnly': True })) thing.add_property( Property(thing, 'temperature', celsius, metadata={ '@type': 'LevelProperty', 'title': 'Temperature', 'type': 'number', 'unit': '°C', 'readOnly': True })) server = WebThingServer(SingleThing(thing), port=8889) def update(): h, t = sht.all() celsius.notify_of_external_update(t.C) humidity.notify_of_external_update(h.RH) timer = tornado.ioloop.PeriodicCallback(update, 3000) timer.start() try: logging.info('starting the server') server.start() except KeyboardInterrupt: logging.debug('stopping update task') timer.stop() logging.info('stopping the server') server.stop() logging.info('done')
def initialize_thing(): thing = Thing('urn:dev:ops:smart_lamp_7256', 'SLamp', ['OnOffSwitch', 'Light'], 'A smart lamp connected to the web') thing.add_property( Property(thing, 'on', Value(True), metadata={ '@type': 'SwitchProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'Shows if the lamp is on', })) thing.add_property( Property(thing, 'brightness', Value(50), metadata={ '@type': 'BrightnessProperty', 'title': 'Brightness', 'type': 'integer', 'description': 'The light level from 0 to 100', 'minimum': 0, 'maximum': 100, 'unit': 'percent', })) thing.add_available_action( 'change_brightness', { 'title': 'Change Brightness', 'description': "Change the lamp brightness to a given level", 'input': { 'type': 'object', 'required': [ 'brightness', ], 'properties': { 'brightness': { 'type': 'integer', 'minimum': 0, 'maximum': 100, 'unit': 'percent', }, }, }, }, ChangeBrightnessAction) return thing
class FakeGpioHumiditySensor: """A humidity sensor which updates its measurement every few seconds.""" def __init__(self): self.thing = Thing('My Humidity Sensor', 'multiLevelSensor', 'A web connected humidity sensor') self.thing.add_property( Property(self.thing, 'on', Value(True), metadata={ 'type': 'boolean', 'description': 'Whether the sensor is on', })) self.level = Value(0.0) self.thing.add_property( Property(self.thing, 'level', self.level, metadata={ 'type': 'number', 'description': 'The current humidity in %', 'unit': '%', })) self.ioloop = tornado.ioloop.IOLoop.current() t = threading.Thread(target=self.update_level) t.daemon = True t.start() def update_level(self): while True: time.sleep(3) # Update the underlying value, which in turn notifies all listeners self.ioloop.add_callback(self.level.notify_of_external_update, self.read_from_gpio()) @staticmethod def read_from_gpio(): """Mimic an actual sensor updating its reading every couple seconds.""" return 70.0 * random.random() * (-0.5 + random.random()) def get_thing(self): return self.thing
def run_server(): ds18 = DS18B20('28-011458c437aa') celsius = Value(ds18.temperature().C) thing = Thing( 'urn:dev:ops:temperature-sensor', 'DS18B20_Anthony', ['TemperatureSensor']) thing.add_property( Property( thing, 'celsius', celsius, metadata={ '@type': 'TemperatureProperty', 'title': 'Celsius', 'type': 'number', 'unit': '°C', 'readOnly': True })) server = WebThingServer(SingleThing(thing), port=8888) def update(): t = ds18.temperature() celsius.notify_of_external_update(t.C) timer = tornado.ioloop.PeriodicCallback(update, 3000) timer.start() try: logging.info('starting the server') server.start() except KeyboardInterrupt: logging.debug('stopping update task') timer.stop() logging.info('stopping the server') server.stop() logging.info('done')
def make_thing(): thing = Thing('urn:dev:ops:my-lamp-1234', 'My pi Led', ['OnOffSwitch', 'Light'], 'A web connected Led') thing.add_property( Property(thing, 'on', Value(True, lambda v: GPIO.output(led, v)), metadata={ '@type': 'OnOffProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_available_event( 'overheated', { 'description': 'The lamp has exceeded its safe operating temperature', 'type': 'number', 'unit': 'degree celsius', }) return thing
def make_thing(): """ Build WebThing for awox-light """ thing = Thing('urn:dev:ops:my-awox-light-1234', 'Awox Light', ['OnOffSwitch', 'Light'], 'A web connected lamp') thing.add_property( Property(thing, 'on', Value(True, lambda v: controller.on() if v else controller.off()), metadata={ '@type': 'OnOffProperty', 'label': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_property( Property(thing, 'brightness', Value(50, lambda v: controller.setColorBrightness(int(v))), metadata={ '@type': 'BrightnessProperty', 'label': 'Brightness', 'type': 'number', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, 'unit': 'percent', })) thing.add_property( Property(thing, 'color', Value('#ffffff', lambda v: set_color(v)), metadata={ '@type': 'ColorProperty', 'label': 'Color', 'type': 'string', 'description': 'Color of light', })) return thing
def make_thing(): thing = Thing('My Lamp', ['OnOffSwitch', 'Light'], 'A web connected lamp') thing.add_property( Property(thing, 'on', Value(True), metadata={ '@type': 'OnOffProperty', 'label': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_property( Property(thing, 'brightness', Value(50), metadata={ '@type': 'BrightnessProperty', 'label': 'Brightness', 'type': 'integer', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, 'unit': 'percent', })) thing.add_available_action( 'fade', { 'label': 'Fade', 'description': 'Fade the lamp to a given level', 'input': { 'type': 'object', 'required': [ 'brightness', 'duration', ], 'properties': { 'brightness': { 'type': 'integer', 'minimum': 0, 'maximum': 100, 'unit': 'percent', }, 'duration': { 'type': 'integer', 'minimum': 1, 'unit': 'milliseconds', }, }, }, }, FadeAction) thing.add_available_event( 'overheated', { 'description': 'The lamp has exceeded its safe operating temperature', 'type': 'number', 'unit': 'degree celsius', }) return thing
class PiCameraWebThing: """A Web Thing enabled raspberry pi camera""" def __init__(self): self.conf = anyconfig.load([DEFAULT_CONFIG, USER_CONFIG], ignore_missing=True, ac_merge=anyconfig.MS_REPLACE) self.ioloop = tornado.ioloop.IOLoop.current() self.device_name = self.conf['name'] self.port = self.conf['port'] self.si7021_enabled = self.conf['si7021']['enabled'] self.sensors_update_interval = self.conf['sensors']['update_interval'] self.use_video_port = self.conf['camera']['use_video_port'] self.framerate = self.conf['camera']['framerate'] self.iso = self.conf['camera']['iso'] self.rotation = self.conf['camera']['rotation'] self.shutter_speed = self.conf['camera']['shutter_speed'] self.sensor_mode = self.conf['camera']['sensor_mode'] self.exposure_mode = self.conf['camera']['exposure_mode'] self.resolution = self.conf['camera']['resolution'] """ Only 3 camera settings are exposed as Thing properties, to avoid creating a clutter of unnecessary Detail bubbles in the Gateway interface """ self.resolution_value = Value( self.resolution, lambda resolution: self.set_resolution(resolution)) self.framerate_value = Value( self.framerate, lambda framerate: self.set_framerate(framerate)) self.exposure_mode_value = Value( self.exposure_mode, lambda mode: self.set_exposure_mode(mode)) self.base64_still_image_value = Value("") self.temperature_value = Value(0.0) self.humidity_value = Value(0.0) self.resolution_property = None self.framerate_property = None self.exposure_mode_property = None self.base64_still_image_property = None self.temperature_property = None self.humidity_property = None logger.info('Starting PiCamera Web Thing: %s', self.device_name) self.sensor_setup() self.camera_setup() self.webthing_setup() def start(self): self.server.start() def stop(self): self.server.stop() def cleanup(self): self.camera.stop_preview() self.camera.close() def camera_setup(self): """ Starts a background thread for handling camera captures """ self.camera = picamera.PiCamera() self.camera_lock = threading.Lock() with self.camera_lock: self.camera.resolution = self.resolution self.camera.rotation = self.rotation self.camera.iso = self.iso """ We set the framerate to 30.0 at startup so the firmware has at least 90 frames (30 * 3 seconds) to use for calibrating the sensor, which is critical in low light. May need to do this periodically as well; if the framerate is set very low the camera will take several minutes or longer to react to lighting changes """ self.camera.framerate = 30.0 self.camera.shutter_speed = self.shutter_speed self.camera.sensor_mode = self.sensor_mode self.camera.exposure_mode = self.exposure_mode # may not be necessary, night mode seems to do it automatically #self.camera.framerate_range = (0.1, self.framerate) self.camera.start_preview() logger.info('Waiting for camera module warmup...') """ Give the camera firmware a chance to calibrate the sensor, critical for low light """ time.sleep(3) with self.camera_lock: """ now set the framerate back to the configured value """ self.camera.framerate = self.framerate self.camera_thread = threading.Thread(target=self.camera_loop) self.camera_thread.daemon = True self.camera_thread.start() def get_still_image(self): """ This uses base64 for the image data so the gateway doesn't have to do anything but pass it to the `img` tag using the well known inline syntax """ _image_stream = io.BytesIO() logger.debug("Capturing image <use_video_port:%s>", self.use_video_port) with self.camera_lock: # image quality higher than 10 tends to make large images with no # meaningful quality improvement. cap_start = time.time() self.camera.capture(_image_stream, format='jpeg', quality=10, thumbnail=None, use_video_port=self.use_video_port) cap_end = time.time() logger.debug("Capture took %f seconds", (cap_end - cap_start)) _image_stream.seek(0) image = base64.b64encode(_image_stream.getvalue()) _image_stream.close() return image def get_resolution(self): """ This formats the resolution as WxH, which the picamera API will actually accept when setting the value in set_resolution(), so it works out quite well as we can pass resolution back and forth all the way up to the Gateway interface as-is without any further parsing or formatting """ with self.camera_lock: _width, _height = self.camera.resolution resolution = "{}x{}".format(_width, _height) return resolution def set_resolution(self, resolution): with self.camera_lock: try: self.camera.resolution = resolution self.resolution = resolution return True except Exception as e: logger.exception("Failed to set resolution") return False def get_framerate(self): with self.camera_lock: _fr = float(self.camera.framerate) framerate = "{}".format(_fr) return framerate def set_framerate(self, framerate): with self.camera_lock: try: self.camera.framerate = framerate self.framerate = framerate return True except Exception as e: logger.exception("Failed to set framerate") return False def get_exposure_mode(self): with self.camera_lock: _ex = self.camera.exposure_mode return _ex def set_exposure_mode(self, exposure_mode): with self.camera_lock: try: self.camera.exposure_mode = exposure_mode self.exposure_mode = exposure_mode return True except Exception as e: logger.exception("Failed to set exposure mode") return False def camera_loop(self): """ Camera loop """ logger.info('Camera loop running') while True: try: image = self.get_still_image() if self.base64_still_image_value is not None and image is not None: self.ioloop.add_callback( self.base64_still_image_value. notify_of_external_update, image.decode('utf-8')) except Exception as e: logger.exception( 'Exception occured while updating image property') try: resolution = self.get_resolution() if self.resolution_value is not None and resolution is not None: self.ioloop.add_callback( self.resolution_value.notify_of_external_update, resolution) except Exception as e: logger.exception( 'Exception occured while updating resolution property') try: framerate = self.get_framerate() if self.framerate_value is not None and framerate is not None: self.ioloop.add_callback( self.framerate_value.notify_of_external_update, framerate) except Exception as e: logger.exception( 'Exception occured while updating framerate property') try: exposure_mode = self.get_exposure_mode() if self.exposure_mode_value is not None and exposure_mode is not None: self.ioloop.add_callback( self.exposure_mode_value.notify_of_external_update, exposure_mode) except Exception as e: logger.exception( 'Exception occured while updating exposure_mode property') wait_interval = 1.0 / float(self.framerate) logger.debug("Camera sleeping for %.2f (fps: %.2f)", wait_interval, float(self.framerate)) time.sleep(wait_interval) def webthing_setup(self): self.thing = Thing(name=self.device_name, type_='camera', description='A Web Thing enabled PiCamera') self.resolution_property = Property( self.thing, 'resolution', metadata={ 'type': 'choice', 'unit': '', 'choices': [ '320x240', '640x480', '800x600', '1024x768', '1296x972', '1640x1232', '3280x2464' ], 'friendlyName': 'Resolution', 'description': 'The current camera resolution', }, value=self.resolution_value) self.thing.add_property(self.resolution_property) self.framerate_property = Property(self.thing, 'framerate', metadata={ 'type': 'choice', 'unit': 'FPS', 'choices': [ "0.0", "0.1", "0.5", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "15.0", "20.0", "30.0" ], 'friendlyName': 'Framerate', 'description': 'The current camera frame rate', }, value=self.framerate_value) self.thing.add_property(self.framerate_property) self.base64_still_image_property = Property( self.thing, 'stillImage', metadata={ 'type': 'stillImage', 'unit': 'base64', 'friendlyName': 'Image', 'description': 'A still image from the camera', }, value=self.base64_still_image_value) self.thing.add_property(self.base64_still_image_property) sorted_exposure_modes = sorted( picamera.PiCamera.EXPOSURE_MODES, key=picamera.PiCamera.EXPOSURE_MODES.__getitem__) self.exposure_mode_property = Property( self.thing, 'exposureMode', metadata={ 'type': 'choice', 'unit': '', 'choices': sorted_exposure_modes, 'friendlyName': 'Exposure', 'description': 'A still image from the camera', }, value=self.exposure_mode_value) self.thing.add_property(self.exposure_mode_property) if self.si7021_enabled: logger.info("Temperature/humidity properties enabled") self.temperature_property = Property( self.thing, 'temperature', metadata={ 'type': 'label', 'unit': '°', 'friendlyName': 'Temperature', 'description': 'The current camera temperature', }, value=self.temperature_value) self.thing.add_property(self.temperature_property) self.humidity_property = Property( self.thing, 'humidity', metadata={ 'type': 'label', 'unit': '%', 'friendlyName': 'Humidity', 'description': 'The current camera humidity level', }, value=self.humidity_value) self.thing.add_property(self.humidity_property) self.server = WebThingServer([self.thing], port=self.port) def sensor_setup(self): if self.si7021_enabled: self.sensor_thread = threading.Thread(target=self.sensor_loop) self.sensor_thread.daemon = True self.sensor_thread.start() def get_si7021_values(self): temperature = None humidity = None try: # Get I2C bus bus = smbus.SMBus(1) # SI7021 address, 0x40(64) # 0xF5(245) Select Relative Humidity NO HOLD master mode bus.write_byte(0x40, 0xF5) time.sleep(0.3) # SI7021 address, 0x40(64) # Read data back, 2 bytes, Humidity MSB first data0 = bus.read_byte(0x40) data1 = bus.read_byte(0x40) # Convert the data humidity = ((data0 * 256 + data1) * 125 / 65536.0) - 6 time.sleep(0.3) # SI7021 address, 0x40(64) # 0xF3(243) Select temperature NO HOLD master mode bus.write_byte(0x40, 0xF3) time.sleep(0.3) # SI7021 address, 0x40(64) # Read data back, 2 bytes, Temperature MSB first data0 = bus.read_byte(0x40) data1 = bus.read_byte(0x40) # Convert the data temperature = ((data0 * 256 + data1) * 175.72 / 65536.0) - 46.85 # Convert celsius to fahrenheit temperature = (temperature * 1.8) + 32 except Exception as e: logger.exception("Failed to get si7021 sensor data") return temperature, humidity def sensor_loop(self): """ Sensor loop """ logger.info('Sensor loop running') while True: try: temperature = None humidity = None if self.si7021_enabled: temperature, humidity = self.get_si7021_values() if self.temperature_value is not None and temperature is not None: self.ioloop.add_callback( self.temperature_value.notify_of_external_update, temperature) if self.humidity_value is not None and humidity is not None: self.ioloop.add_callback( self.humidity_value.notify_of_external_update, humidity) except Exception as e: logger.exception( 'Exception occured while updating sensor properties') time.sleep(self.sensors_update_interval)
def make_thing(): thing = Thing( 'urn:dev:ops:my-lamp-1234', 'My Simple Lamp', ['OnOffSwitch', 'Light'], 'A web connected lamp' ) thing.add_property( Property(thing, 'on', Value(True, lambda v: logging.debug("On-state is now %s" % v)), metadata={ '@type': 'OnOffProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_property( Property(thing, 'brightness', Value(50, lambda v: logging.debug("Brightness is now %d" % v)), metadata={ '@type': 'BrightnessProperty', 'title': 'Brightness', 'type': 'integer', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, 'unit': 'percent', })) thing.add_property( Property(thing, "URL", Value(None), metadata={ '@type': 'ImageProperty', 'title': 'Image URL', 'type': 'null', 'description': 'URL of the image to be played', 'links': [{ 'rel': 'alternate', 'href': '/static/current.jpg', 'mediaType': 'image/jpeg', }, ], })) thing.add_available_action( 'fade', { 'title': 'Fade', 'description': 'Fade the lamp to a given level', 'input': { 'type': 'object', 'required': [ 'brightness', 'duration', ], 'properties': { 'brightness': { 'type': 'integer', 'minimum': 0, 'maximum': 100, 'unit': 'percent', }, 'duration': { 'type': 'integer', 'minimum': 1, 'unit': 'milliseconds', }, }, }, }, FadeAction) thing.add_available_event( 'overheated', { 'description': 'The lamp has exceeded its safe operating temperature', 'type': 'number', 'unit': 'degree celsius', }) return thing
class ExampleDimmableLight: """A dimmable light that logs received commands to stdout.""" def __init__(self): self.thing = Thing('My Lamp', 'dimmableLight', 'A web connected lamp') self.thing.add_available_action( 'fade', { 'description': 'Fade the lamp to a given level', 'input': { 'type': 'object', 'required': [ 'level', 'duration', ], 'properties': { 'level': { 'type': 'number', 'minimum': 0, 'maximum': 100, }, 'duration': { 'type': 'number', 'unit': 'milliseconds', }, }, } }, FadeAction) self.thing.add_available_event( 'overheated', { 'description': 'The lamp has exceeded its safe operating temperature', 'type': 'number', 'unit': 'celsius' }) self.thing.add_property(self.get_on_property()) self.thing.add_property(self.get_level_property()) def get_on_property(self): return Property(self.thing, 'on', Value(True, lambda v: print('On-State is now', v)), metadata={ 'type': 'boolean', 'description': 'Whether the lamp is turned on', }) def get_level_property(self): return Property(self.thing, 'level', Value(50, lambda l: print('New light level is', l)), metadata={ 'type': 'number', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, }) def get_thing(self): return self.thing
def make_hue_lamp_thing(): # thing init # thing_type = ['OnOffSwitch', 'Light'] thing = Thing( 'lights_1', 'hue_lamp', thing_type, ) # thind properties # thing.add_property( Property(thing, 'on', Value(False), metadata={ '@type': 'OnOffProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'Whether the lamp is turned on', })) thing.add_property( Property(thing, 'brightness', Value(0), metadata={ '@type': 'BrightnessProperty', 'title': 'Brightness', 'type': 'integer', 'description': 'The level of light from 0-100', 'minimum': 0, 'maximum': 100, 'unit': 'percent', })) thing.add_property( Property(thing, 'color', Value('white'), metadata={ '@type': 'Color', 'title': 'Light color', 'type': 'string', 'description': 'Lamp Color', })) # thing actions # thing.add_available_action( 'on', { 'title': 'OnAction', 'description': 'Turn the lamp on', 'metadata': { 'input': { 'type': 'None' } } }, OnAction) thing.add_available_action( 'off', { 'title': 'OffAction', 'description': 'Turn the lamp off', 'metadata': { 'input': { 'type': 'None' } } }, OffAction) thing.add_available_action( 'color', { 'title': 'ChangeColor', 'description': 'Change hue_light color', 'metadata': { 'input': { 'type': 'object', 'required': ['color'] } } }, ChangeColor) return thing
class testThing(): def __init__(self, port, propertyclass=myProperty, msgq=None): self.port = port #self.hostname = '%s.local' % socket.gethostname() self.hostname = get_ip() self.tid = 'http---%s-%s' % (self.hostname, self.port) self.thing = Thing('urn:dev:ops:my-testthing-%s' % port, 'a testThing on port %s' % port, ['testThing'], 'A native webthing for testing') self.msgq = msgq self.thing.add_property( propertyclass(self.thing, 'on', Value(True), metadata={ '@type': 'OnOffProperty', 'title': 'On/Off', 'type': 'boolean', 'description': 'A boolean property of the thing', }, msgq=msgq, msgprefix=self.tid)) self.thing.add_property( propertyclass(self.thing, 'idx', Value(0), metadata={ '@type': 'IndexProperty', 'title': 'Index', 'type': 'integer', 'description': 'A numerical index of the thing', 'minimum': 0, 'maximum': 10000, 'unit': 'bar', }, msgq=msgq, msgprefix=self.tid)) def to_thing_POST_body(self): properties = {} for prop in self.thing.properties: properties[prop] = self.thing.properties[prop].get_metadata() properties[prop]['links'] = [{ 'rel': 'property', 'href': '/properties/%s' % prop, 'proxy': True }] json = { 'id': self.tid, 'title': 'testThing on %s:%s' % (self.hostname, self.port), '@context': self.thing.context, '@type': self.thing.type, 'properties': properties, 'links': [], 'baseHref': 'http://%s:%s' % (self.hostname, self.port), 'pin': { 'required': False, 'pattern': 0 }, 'credentialsRequired': False, 'description': self.thing.description, 'actions': {}, 'events': {}, 'selectedCapability': 'Light', } return json def get_thing(self): return self.thing def get_tid(self): return self.tid def handle_msgs(self, msgq): '''IPC to call a method on the Thing''' while True: msg = msgq.get() (tid, method, args) = msg if tid == self.tid: _method = getattr(self.thing, method) _method(*args)
def run_server(): ds18 = DS18B20('28-03199779f5a1') ds18_celsius = Value(ds18.temperature().C) ds18_thing = Thing('urn:dev:ops:temperature-sensor', 'Temperature Sensor', ['TemperatureSensor']) ds18_thing.add_property( Property(ds18_thing, 'celsius', ds18_celsius, metadata={ '@type': 'TemperatureProperty', 'title': 'Celsius', 'type': 'number', 'unit': '°C', 'readOnly': True })) sht = SHT20(1, 0x40) h, t = sht.all() sht_celsius = Value(t.C) sht_rh = Value(h.RH) sht_thing = Thing('urn:dev:ops:humidity-temperature-sensor', 'Humidity and Temperature Sensor', ['MultiLevelSensor', 'TemperatureSensor']) # If you want icon to show humidity: # - remove type `TemperatureSensor`, and # - change temperature metadata @type to `LevelProperty` sht_thing.add_property( Property(sht_thing, 'humidity', sht_rh, metadata={ '@type': 'LevelProperty', 'title': 'Relative humidity', 'type': 'number', 'unit': 'percent', 'readOnly': True })) sht_thing.add_property( Property(sht_thing, 'temperature', sht_celsius, metadata={ '@type': 'TemperatureProperty', 'title': 'Celsius', 'type': 'number', 'unit': '°C', 'readOnly': True })) server = WebThingServer(MultipleThings([ds18_thing, sht_thing], 'Multi-sensor Device'), port=8888) def update(): t = ds18.temperature() ds18_celsius.notify_of_external_update(t.C) h, t = sht.all() sht_celsius.notify_of_external_update(t.C) sht_rh.notify_of_external_update(h.RH) timer = tornado.ioloop.PeriodicCallback(update, 3000) timer.start() try: logging.info('starting the server') server.start() except KeyboardInterrupt: logging.debug('stopping update task') timer.stop() logging.info('stopping the server') server.stop() logging.info('done')