[RFC] IoT frameworks

Nikolay Khabarov Nikolay.Khabarov at dataart.com
Thu Apr 2 20:53:49 UTC 2015


Hello,


I’d like to share with you some ideas along with some practical implementations of Ubuntu Snappy Core Frameworks for developing IoT apps as set of abstractions to provide access to standard things like simple hardware interfaces (GPIO, UART, I2C), wireless protocols (Bluetooth Low Energy, ZigBee, EnOcean), cloud services, devices connected via this interfaces etc.​ With all of that architects and developers will be able to mash up various APIs on edge devices, bridge local protocols and peripherals into the cloud, or run event based logic on edge device.


Imagine the task when you need to connect a Bluetooth Low Energy (BLE) switch to control a BLE light bulb and at the same time, have the ability to turn lights on or off remotely, through a web app. Without frameworks you will have to rely on language/platform specific libraries to work with BLE, and cloud platform and carry these dependencies with your snaps, compile low-level libraries for different architectures increasing overall complexity of the solution. That’s how things are currently done with OpenWRT, Raspbian, BeagleBone, etc.


Having these Frameworks and Ubuntu Snappy Core you will have to: install BLE framework snap, add BLE Bulb and Switch profile Framework Snaps, then you will have to write app code like:


def toggle():

 bulb = dbus.SystemBus().get_object("com.devicehive.ble.bulb", "com/devicehive/ble/bulb")

 mac = bulb.scan()

 if mac:

   bulb.toggle(mac)


DBusGMainLoop(set_as_default=True)

sw = dbus.SystemBus().get_object("com.devicehive.ble.switch", "com/devicehive/ble/switch")

mac = sw.scan()

sw.connect_to_signal(mac, "clicked", toggle)

GObject.MainLoop().run()


We are taking Python as a meta-language, but same concepts, can be applied to Go, Node.js, C++, or even shell script.


Now developer can publish a Snap into Ubuntu Snappy store for further use. As you can see we suggest to use dbus as interface for frameworks making it the only dependency. Lots of programming languages already have dbus bindings, some of them, with dynamic typing like Python or Node.js, can provide syntax of converting method calls into d-bus calls.


Another example, more low-level, might be connecting simple hardware chips. Dallas DS18B20 for example. It has 1-wire protocol and each developer who want to use it can start do in a few sec with such frameworks. Just install 1-wire framework(1-wire interface implementation) and ds18b20 framework (chip protocol implementation for 1-wire interface) and the to find out a temperature just call:


sensor = dbus.SystemBus().get_object("com.devicehive.1wire.ds18b20", "com/devicehive/1wire/ds18b20")

sensor.get_temperature()


As it can be seen from examples above, instead of carrying over dependencies, Frameworks can be installed through standard snappy deployment mechanism and provide the same developer experience of hardware and cloud abstraction across different languages and different SoCs.


I think it's possible to imagine plenty of other usages. More detailed description of idea you can find here: https://docs.google.com/a/devicehive.com/document/d/1XxXMZx5ff8x05p92zdly8Av7LhWKQwywUdLG4v83-zc/edit?usp=sharing​


To prove the idea, I've implemented simple GPIO framework. It works on real hardware - http://youtu.be/4RsMiQU_LMM​


code of framework is here: https://github.com/devicehive/IoT-framework-gpio/blob/master/src/daemon/gpio-daemon

code of examples: https://github.com/devicehive/IoT-framework-gpio/tree/master/src/examples​

dbus specification: https://github.com/devicehive/IoT-framework-gpio/blob/master/DBUS-SPEC.md


You can also download prebuilt snaps for it and play:

framework snap: https://drive.google.com/a/devicehive.com/file/d/0B9jKFl3qYG3paFVzekR6bzhYamc/view?usp=sharing

examples snap: https://drive.google.com/a/devicehive.com/file/d/0B9jKFl3qYG3pdXBDOUd3Nm5ycjQ/view?usp=sharing


Currently to run it on Ubuntu Snappy you need to modify /etc/dbus-1/system.conf - change 'deny' to 'allow' in this two lines

<deny own=*" />

<deny send_type="method_call" />


Another quick example is building s Snap that relies on BLE and EnOcean Frameworks to control a BLE bulb with a wireless switch without any battery power, generating energy to transmit signals through mechanical force: http://www.youtube.com/watch?v=S-sbMeetzL0


Provided there are EnOcean and BLE frameworks, the code looks like this and can be transferred across different platforms and re-created in different languages having only dbus binding as a dependency.


==================================

#!/usr/bin/python3


import dbus

from dbus.mainloop.glib import DBusGMainLoop

from gi.repository import GObject

import json


DBUS_BUS_ENOCEAN_NAME = 'com.devicehive.enocean'

DBUS_BUS_BLE_NAME = 'com.devicehive.bluetooth'


SWITCH_ADDRESS = '00:2A:1A:B8'

BULB_ADDRESS = 'F4:04:4C:0C:58:A3'


bulb_on_value = '0f0d0300ffffffc800c800c8000059ffff'

bulb_off_value = '0f0d0300ffffff0000c800c8000091ffff'

bulb_handle = 0x002b


DBusGMainLoop(set_as_default=True)



def init_bulb():

   bus = dbus.SystemBus()

   ble_manager = bus.get_object(DBUS_BUS_BLE_NAME, '/')

   bulb_path = ble_manager.Create(BULB_ADDRESS, dbus_interface='com.devicehive.BluetoothManager')

   return bus.get_object(DBUS_BUS_BLE_NAME, bulb_path)


bulb = init_bulb()



def turn_bulb(on):

   if on:

       print('ON')

       bulb.Write(bulb_handle, bulb_on_value, False, dbus_interface='com.devicehive.BluetoothDevice')

   else:

       print('OFF')

       bulb.Write(bulb_handle, bulb_off_value, False, dbus_interface='com.devicehive.BluetoothDevice')



def message_received(value):

   res = json.loads(value)

   if res['sender'] == SWITCH_ADDRESS:

       if res['R1']['raw_value'] == 2:

           turn_bulb(True)


       if res['R1']['raw_value'] == 3:

           turn_bulb(False)



def main():

   bus = dbus.SystemBus()

   enocean_manager = bus.get_object(DBUS_BUS_ENOCEAN_NAME, '/com/devicehive/enocean')

   enocean = dbus.Interface(enocean_manager, DBUS_BUS_ENOCEAN_NAME)

   enocean.connect_to_signal('message_received', message_received)


   try:

       GObject.MainLoop().run()

   except KeyboardInterrupt:

       pass



if __name__ == '__main__':

   main()


==================================


Thanks,

  Nikolay Khabarov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/snappy-devel/attachments/20150402/af2eedc2/attachment-0001.html>


More information about the snappy-devel mailing list