This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PyACI Serial Configuration and Model Subscription

Hello,

In a nut shell i am try to get a Model in PyACI to subscribe to a group address and display events. i have had limited success. and will try to explain as best i can. thankyou for your help.

i have successfully completed all steps in the Interactive mesh provisioning and configuration 

we are using two PCA10040 / nrf52832 DK's. loaded with:
examples/serial/serial_nrf52832_xxAA_s132_6.0.0_merged.hex
examples/light_switch/client/light_switch_client_nrf52832_xxAA_s132_6.0.0_merged.hex

i have created a custom Generic On Off Server model in models/generic_on_off_server.py

from mesh.access import Model, Opcode
from models.common import TransitionTime
import struct

class GenericOnOffServer(Model):
    GENERIC_ON_OFF_SET = Opcode(0x8202, None, "Generic OnOff Set")
    GENERIC_ON_OFF_SET_UNACKNOWLEDGED = Opcode(0x8203, None, "Generic OnOff Set Unacknowledged")
    GENERIC_ON_OFF_GET = Opcode(0x8201, None, "Generic OnOff Get")
    GENERIC_ON_OFF_STATUS = Opcode(0x8204, None, "Generic OnOff Status")
    MESH_MESSAGE_RECEIVED_SUBSCRIPTION = Opcode(0xD1)

    def __init__(self):
        self.opcodes = [
            (self.GENERIC_ON_OFF_GET, self.__event_handler),
            (self.GENERIC_ON_OFF_SET, self.__event_handler),
            (self.GENERIC_ON_OFF_SET_UNACKNOWLEDGED, self.__event_handler),
            (self.MESH_MESSAGE_RECEIVED_SUBSCRIPTION, self.__event_handler)]
        self.__tid = 0
        super(GenericOnOffServer, self).__init__(self.opcodes)

    @property
    def _tid(self):
        tid = self.__tid
        self.__tid += 1
        if self.__tid >= 255:
            self.__tid = 0
        return tid

    def __event_handler(self, opcode, message):
        print("Server Event {} {}".format(opcode, message))
        self.logger.info("Server EVent {} {}".format(opcode, message))

i can think configure this using interactive_pyaci.py with the following commands.

In [1]: db = MeshDB("database/example_database.json")
In [2]: p = Provisioner(device, db)
# SubnetAdd: {'subnet_handle': 0}
# AppkeyAdd: {'appkey_handle': 0}
# AppkeyAdd: {'appkey_handle': 1}
In [3]: p.scan_start()
# Received UUID 0059ccaa0000000076e52d5e787484ee with RSSI: -23 dB
In [4]: p.scan_stop()                                                                                                                                                            
In [5]: p.provision(name="switch")                                                                                                                                               
# DevkeyAdd: {'devkey_handle': 8}
# AddrPublicationAdd: {'address_handle': 0}
In [6]: cc = ConfigurationClient(db)
In [7]: device.model_add(cc)
In [8]: cc.publish_set(8, 0)
In [9]: cc.composition_data_get()
#{ .... }
In [10]: cc.appkey_add(0)                                                                                                                                                        
In [11]: cc.model_app_bind(db.nodes[0].unicast_address+1, 0, mt.ModelId(0x1001))                                                                                                 
# config database should now looks as follows
"nodes": [
    {
      "UUID": "0059ccaa0000000076e52d5e787484ee",
      "appKeys": [
        0
      ],
      "cid": "0059",
      "configComplete": false,
      "crpl": 40,
      "deviceKey": "a52fc2a9e75ed237b49872e571c010d2",
      "elements": [
        {
          "index": 0,
          "location": "0000",
          "models": [
            {
              "modelId": "0000"
            },
            {
              "modelId": "0002"
            }
          ]
        },
        {
          "index": 1,
          "location": "0000",
          "models": [
            {
              "bind": [
                0
              ],
              "modelId": "1001",
              "publish": {
                "address": 49153,
                "credentials": 0,
                "index": 0,
                "period": 0,
                "retransmit": {
                  "count": 0,
                  "interval": 50
                },
                "ttl": 1
              }
            }
          ]
        },
        {
          "index": 2,
          "location": "0000",
          "models": [
            {
              "modelId": "1001"
            }
          ]
        }
    ],
In [13]: device = d[0]                                                                                                                                                           
In [13]: device.event_filter_disable()                                                                                                                                           
In [14]: device.send(cmd.AddrSubscriptionAdd(db.groups[0].address))                                                                                                              
# AddrSubscriptionAdd: {'address_handle': 1}

# it should now be possible to see the events appear in the console when the buttons 1 and 2 are press on the light switch DK
# if they do not appear try changing logging levels to debug
# press
# DEBUG - ttyACM0: parsed_packet {event: MeshMessageReceivedSubscription, data: {'src': 17, 'dst': 1, 'appkey_handle': 0, 'subnet_handle': 0, 'ttl': 1, 'adv_addr_type': 1, 'adv_addr': bytearray(b'\xf4\xc0\x02\x12*\xdf'), 'rssi': -18, 'actual_length': 6, 'data': bytearray(b'\x82\x02\x01\x00\x01\n')}}

# however these event are not connected to the GenericOnOffServer Model because it has not been created yet

In [15]: gs = GenericOnOffServer()                                                                                                                                               
In [16]: device.model_add(gs)                                                                                                                                                    
In [18]: gs.publish_set(8, 0)       # not sure this is nessisary as this model never publishes events

this is where my confusion starts.

the GenericOnOffServer model was not required to get the events to appears in the log.
it was the AddrSubscriptionAdd serial command which caused the events to appear.

device.send(cmd.AddrSubscriptionAdd(db.groups[0].address))

and the events never make it to the GenericOnOffServer model.
now this somewhat makes sense because the model would have to have the group address in its subscriptions. which has never been set.

i considered / tried using Access Layer Model Subs Add serial command but this didnt not work because i did not know the Handle for the model.

this made me realize the models implemented in PyACI / serial API must work very differently to models embedded on a device.
they have no model ID, no subscriptions, and can not have any configuration commands run against them from a mesh configuration client.

so questions:

  1. is my configuration correct? have I missed any steps that would allow these events to be passed though to the Model? or is this the expected behavior?

if the is the expected behavior then:

Parents
  • I was able to receive the the events from a Generic OnOff Client model (external chip) by executing the same steps as you, except for one additional command:

    cc.model_publication_set(db.nodes[0].unicast_address+1, mt.ModelId(0x1001),mt.Publish(db.groups[0].address, index=0, ttl=1))

    This will make the Generic OnOff client model publish its event to group address 0 (from example_database.json). Then, if an interactive python session is running, you will receive a message similar as below:

    2018-12-03 15:16:52,996 - INFO - COM7: {event: MeshMessageReceivedSubscription, data: {'src': 17, 'dst': 1, 'appkey_handle': 0, 'subnet_handle': 0, 'ttl': 1, 'adv_addr_type': 1, 'adv_addr': bytearray(b'L\x9e\xfe \x83\xd4'), 'rssi': -60, 'actual_length': 6, 'data': bytearray(b'\x82\x02\x01\t\x01\n')}}

    I am not sure how to correctly forward the events to the Generic OnOff Server model, but here is my guess: Add the GenericOnOffServer class to interactive_pyaci.py, and create an object, then modify the event handler in the Interactive class to forward the events to the GenericOnOffServer class.

    I will ask somebody with more knowledge about this, and give you an update if needed.

    Best regards,

    Simon

    UPDATE (12.10.2018):

    In addition to what I have mentioned (i.e. to see the events in the pyACI log), you will need to add the event filter to forward these events.

Reply
  • I was able to receive the the events from a Generic OnOff Client model (external chip) by executing the same steps as you, except for one additional command:

    cc.model_publication_set(db.nodes[0].unicast_address+1, mt.ModelId(0x1001),mt.Publish(db.groups[0].address, index=0, ttl=1))

    This will make the Generic OnOff client model publish its event to group address 0 (from example_database.json). Then, if an interactive python session is running, you will receive a message similar as below:

    2018-12-03 15:16:52,996 - INFO - COM7: {event: MeshMessageReceivedSubscription, data: {'src': 17, 'dst': 1, 'appkey_handle': 0, 'subnet_handle': 0, 'ttl': 1, 'adv_addr_type': 1, 'adv_addr': bytearray(b'L\x9e\xfe \x83\xd4'), 'rssi': -60, 'actual_length': 6, 'data': bytearray(b'\x82\x02\x01\t\x01\n')}}

    I am not sure how to correctly forward the events to the Generic OnOff Server model, but here is my guess: Add the GenericOnOffServer class to interactive_pyaci.py, and create an object, then modify the event handler in the Interactive class to forward the events to the GenericOnOffServer class.

    I will ask somebody with more knowledge about this, and give you an update if needed.

    Best regards,

    Simon

    UPDATE (12.10.2018):

    In addition to what I have mentioned (i.e. to see the events in the pyACI log), you will need to add the event filter to forward these events.

Children
  • I found that the messages coming in doing the above process are Subscription and not Unicast. Therefore to forward the data onto the Server model (or any model in that case) needs the following change to Access.__event_handler() in access.py line 212. [Mesh SDK v3.10]

    # old
    if event._opcode == Event.MESH_MESSAGE_RECEIVED_UNICAST:
    
    # new
    if event._opcode == Event.MESH_MESSAGE_RECEIVED_UNICAST or event._opcode == Event.MESH_MESSAGE_RECEIVED_SUBSCRIPTION:

Related