Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.9 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6957C43387 for ; Sat, 15 Dec 2018 00:26:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C90D6206C0 for ; Sat, 15 Dec 2018 00:26:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730103AbeLOA0k (ORCPT ); Fri, 14 Dec 2018 19:26:40 -0500 Received: from mga17.intel.com ([192.55.52.151]:22249 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730020AbeLOA0k (ORCPT ); Fri, 14 Dec 2018 19:26:40 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 14 Dec 2018 16:26:36 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,355,1539673200"; d="scan'208";a="109640380" Received: from bgix-dell-lap.sea.intel.com ([10.251.138.67]) by fmsmga008.fm.intel.com with ESMTP; 14 Dec 2018 16:26:36 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: johan.hedberg@gmail.com, inga.stotland@intel.com, marcel@holtmann.org, brian.gix@intel.com Subject: [PATCH BlueZ v3 28/30] mesh: Sample On/Off Client and Server Date: Fri, 14 Dec 2018 16:26:22 -0800 Message-Id: <20181215002624.9313-29-brian.gix@intel.com> X-Mailer: git-send-email 2.14.5 In-Reply-To: <20181215002624.9313-1-brian.gix@intel.com> References: <20181215002624.9313-1-brian.gix@intel.com> Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Inga Stotland --- mesh/test/example-onoff-client | 288 ++++++++++++++++++++++++++++++++ mesh/test/example-onoff-server | 365 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 653 insertions(+) create mode 100644 mesh/test/example-onoff-client create mode 100644 mesh/test/example-onoff-server diff --git a/mesh/test/example-onoff-client b/mesh/test/example-onoff-client new file mode 100644 index 000000000..e4a87eb12 --- /dev/null +++ b/mesh/test/example-onoff-client @@ -0,0 +1,288 @@ +#!/usr/bin/env python3 + +import sys +import struct +import numpy +import dbus +import dbus.service +import dbus.exceptions + +try: + from gi.repository import GObject +except ImportError: + import gobject as GObject +from dbus.mainloop.glib import DBusGMainLoop + +MESH_SERVICE_NAME = 'org.bluez.mesh' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' + +MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1' +MESH_NODE_IFACE = 'org.bluez.mesh.Node1' +MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1' + +VENDOR_ID_NONE = 0xffff + +app = None +bus = None +mainloop = None +node = None +token = numpy.uint64(0x76bd4f2372477600) + +def unwrap(item): + if isinstance(item, dbus.Boolean): + return bool(item) + if isinstance(item, (dbus.UInt16, dbus.Int16, dbus.UInt32, dbus.Int32, + dbus.UInt64, dbus.Int64)): + return int(item) + if isinstance(item, dbus.Byte): + return bytes([int(item)]) + if isinstance(item, dbus.String): + return item + if isinstance(item, (dbus.Array, list, tuple)): + return [unwrap(x) for x in item] + if isinstance(item, (dbus.Dictionary, dict)): + return dict([(unwrap(x), unwrap(y)) for x, y in item.items()]) + + print('Dictionary item not handled') + print(type(item)) + return item + +def attach_app_cb(node_path, dict_array): + print('Mesh application registered ', node_path) + print(type(node_path)) + print(type(dict_array)) + print(dict_array) + + els = unwrap(dict_array) + print("Get Elements") + for el in els: + print(el) + idx = struct.unpack('b', el[0])[0] + print('Configuration for Element ', end='') + print(idx) + models = el[1] + + element = app.get_element(idx) + element.set_model_config(models) + + obj = bus.get_object(MESH_SERVICE_NAME, node_path) + global node + node = dbus.Interface(obj, MESH_NODE_IFACE) + +def error_cb(error): + print('D-Bus call failed: ' + str(error)) + +def generic_reply_cb(): + print('D-Bus call done') + +def interfaces_removed_cb(object_path, interfaces): + if not mesh_net: + return + + if object_path == mesh_net[2]: + print('Service was removed') + mainloop.quit() + +class Application(dbus.service.Object): + + def __init__(self, bus): + self.path = '/example' + self.elements = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_element(self, element): + self.elements.append(element) + + def get_element(self, idx): + for ele in self.elements: + if ele.get_index() == idx: + return ele + + @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') + def GetManagedObjects(self): + response = {} + print('GetManagedObjects') + for element in self.elements: + response[element.get_path()] = element.get_properties() + return response + +class Element(dbus.service.Object): + PATH_BASE = '/example/ele' + + def __init__(self, bus, index): + self.path = self.PATH_BASE + format(index, '02x') + print(self.path) + self.models = [] + self.bus = bus + self.index = index + dbus.service.Object.__init__(self, bus, self.path) + + def _get_sig_models(self): + ids = [] + for model in self.models: + id = model.get_id() + vendor = model.get_vendor() + if vendor == VENDOR_ID_NONE: + ids.append(id) + return ids + + def get_properties(self): + return { + MESH_ELEMENT_IFACE: { + 'Index': dbus.Byte(self.index), + 'Models': dbus.Array( + self._get_sig_models(), signature='q') + } + } + + def add_model(self, model): + model.set_path(self.path) + self.models.append(model) + + def get_index(self): + return self.index + + def set_model_config(self, config): + print('Set element models config') + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qqbay", out_signature="") + def MessageReceived(self, source, key, is_sub, data): + print('Message Received on Element ', end='') + print(self.index) + for model in self.models: + model.process_message(source, key, data) + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="qa{sv}", out_signature="") + + def UpdateModelConfiguration(self, model_id, config): + print('UpdateModelConfig ', end='') + print(hex(model_id)) + for model in self.models: + if model_id == model.get_id(): + model.set_config(config) + return + + @dbus.service.method(MESH_ELEMENT_IFACE, + in_signature="", out_signature="") + def get_path(self): + return dbus.ObjectPath(self.path) + +class Model(): + def __init__(self, model_id): + self.cmd_ops = [] + self.model_id = model_id + self.vendor = VENDOR_ID_NONE + self.path = None + + def set_path(self, path): + self.path = path + + def get_id(self): + return self.model_id + + def get_vendor(self): + return self.vendor + + def process_message(self, source, key, data): + print('Model process message') + + def set_publication(self, period): + self.period = period + + def set_bindings(self, bindings): + self.bindings = bindings + + def set_config(self, config): + if 'Bindings' in config: + self.bindings = config.get('Bindings') + print('Bindings: ', end='') + print(self.bindings) + if 'PublicationPeriod' in config: + self.set_publication(config.get('PublicationPeriod')) + print('Model publication period ', end='') + print(self.pub_period, end='') + print(' ms') + +class OnOffClient(Model): + def __init__(self, model_id): + Model.__init__(self, model_id) + self.cmd_ops = { 0x8201, # get + 0x8202, # set + 0x8203 } # set unacknowledged + print('OnOff Client') + + def _reply_cb(state): + print('State ', end=''); + print(state) + + def _send_message(self, dest, key, data, reply_cb): + print('OnOffClient send data') + node.Send(self.path, dest, key, data, reply_handler=reply_cb, + error_handler=error_cb) + + def get_state(self, dest, key): + opcode = 0x8201 + data = struct.pack('