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

Configuring a Vendor Model to work with Serial Example

Hardware: 

  • Raspberry Pi Zero W
  • nRF52840 DK running Serial Example and connected to RPi via USB
  • Custom nRF52840 board acting as a Vendor Model Server

Software:

  • nRF SDK for Mesh v5.0.0

I'm trying to implement a vendor model that is a modified SimpleOnOff Server instance on my custom board. I've set up the opcodes and added it to the element using the guide for SimpleOnOff model. I am able to provision and bind an appkey using the interactive_pyaci guide for provisioning and configuration. However, when I get to this step:

In  [16]: gc.set(True)
2020-03-24 14:51:37,274 - INFO - COM27: PacketSend: {'token': 4}
2020-03-24 14:51:37,303 - INFO - COM27: {event: MeshTxComplete, data: {'token': 4}}
2020-03-24 14:51:37,329 - INFO - COM27.GenericOnOffClient: Present OnOff: on

I do not receive my model's equivalent of the status message from the GenericOnOff example ie. the last line of this snippet. I've already created a python script mirroring generic_on_off.py's implementation:

SET_LIGHT_TEST = Opcode(0xc1, manufacturer_id, "Light Functional Test")
STATUS_GET = Opcode(0xc2, manufacturer_id, "Status Request")
STATUS = Opcode(0xc4, manufacturer_id, "Light Status")
TEST_RESULT = Opcode(0xc5, manufacturer_id, "Light Test RESULT")

 def __init__(self):
        self.opcodes = [
            (self.STATUS, self.__light_status_handler),
            (self.TEST_RESULT, self.__light_test_result_handler)
        ]
    .....
    
 def set(self, state):
        message = bytearray()
        #message += struct.pack("<BB", int(state), self._tid)
        message += struct.pack("<BIHI", 1, 0, 0, 0)
        self.send(self.SET_LIGHT_TEST, message)
    
 def ___light_status_handler(self, opcode, message):
        on_off = "on" if message.data[0] > 0 else "off"
        self.logger.info("Present value is %s", on_off)

    def ___light_test_result_handler(self, opcode, message):
        ack_type, code = struct.unpack("<BL", message)
        self.logger.info("Acknowledgement type: %d, code: %d", ack_type, code)
 

I should get both a status message and a test result message when I call the set method. I do see the message go to my custom board, and it executes the light test successfully. On RTT I was able to find that both access_model_publish() and access_model_reply() returned NRF_INVALID_PARAM. My opcodes are valid so I believe that the model is not being bound to the appkey for some reason. 

Perhaps I need to do something specific with the Configuration Client on interactive_pyaci?

  • Hi,

    I assume you have followed the guide exactly up to that point. Under the step "Adding application keys", what logs do you get when you try to add the application key and bind the model to the application key? 

    Do you get something similar to to guide? 

    In  [11]: cc.appkey_add(0)
    2020-03-24 14:49:11,687 - INFO - COM27: PacketSend: {'token': 2}
    2020-03-24 14:49:11,762 - INFO - COM27: {event: MeshTxComplete, data: {'token': 2}}
    2020-03-24 14:49:11,788 - INFO - COM27.ConfigurationClient: Appkey status: AccessStatus.SUCCESS
    2020-03-24 14:49:11,789 - INFO - COM27.ConfigurationClient: Appkey add 0 succeded for subnet 0 at node 0010
    
    In  [12]: cc.model_app_bind(db.nodes[0].unicast_address, 0, mt.ModelId(0x1000))
    2020-03-24 14:50:45,806 - INFO - COM27: PacketSend: {'token': 3}
    2020-03-24 14:50:45,831 - INFO - COM27: {event: MeshTxComplete, data: {'token': 3}}
    2020-03-24 14:50:45,861 - INFO - COM27.ConfigurationClient: Model app bind status: AccessStatus.SUCCESS
    2020-03-24 14:50:45,862 - INFO - COM27.ConfigurationClient: Appkey bind 0 to model 1000 at 0010

  • Hi,

    Yes I followed it almost exactly, I set the model id to my vendor id with company id as well. This is what I get:

    In  [11]: cc.appkey_add(0)
    2020-03-24 14:49:11,687 - INFO - COM27: PacketSend: {'token': 2}
    2020-03-24 14:49:11,762 - INFO - COM27: {event: MeshTxComplete, data: {'token': 2}}
    2020-03-24 14:49:11,788 - INFO - COM27.ConfigurationClient: Appkey status: AccessStatus.SUCCESS
    2020-03-24 14:49:11,789 - INFO - COM27.ConfigurationClient: Appkey add 0 succeded for subnet 0 at node 0010
    
    In  [12]: cc.model_app_bind(db.nodes[0].unicast_address, 0, mt.ModelId(0xc000, company_id=0x0493))
    2020-03-24 14:50:45,806 - INFO - COM27: PacketSend: {'token': 3}
    2020-03-24 14:50:45,831 - INFO - COM27: {event: MeshTxComplete, data: {'token': 3}}
    2020-03-24 14:50:45,861 - INFO - COM27.ConfigurationClient: Model app bind status: AccessStatus.SUCCESS
    2020-03-24 14:50:45,862 - INFO - COM27.ConfigurationClient: Appkey bind 0 to model 493c000 at 0010

    I do note that sometimes I send one of these commands and I only get the first two lines, so I have to send the command again to receive all four lines. Is this normal?

  • Update: 

    I managed to get a get command working which simply works the same way as the get status function in the Generic OnOff example, in that it uses access_model_reply to send data back. So reply works but not publish...

    In [16]: ex.get()
    
    2021-07-05 03:48:16,766 - INFO - ttyACM0: PacketSend: {'token': 4}
    2021-07-05 03:48:16,784 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 4}}
    2021-07-05 03:48:16,846 - INFO - ttyACM0.LightClient: Present value is off
    In [17]: ex.set(0)
    
    2021-07-05 03:48:30,072 - INFO - ttyACM0: PacketSend: {'token': 5}
    2021-07-05 03:48:30,150 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 5}}
    
    In [18]: ex.get()
    
    2021-07-05 03:49:34,856 - INFO - ttyACM0: PacketSend: {'token': 6}
    2021-07-05 03:49:34,878 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 6}}
    In [19]: ex.get()
    
    2021-07-05 03:49:40,587 - INFO - ttyACM0: PacketSend: {'token': 7}
    2021-07-05 03:49:40,606 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 7}}
    2021-07-05 03:49:40,679 - INFO - ttyACM0.LightClient: Present value is off
    In [20]: ex.get()
    
    2021-07-05 03:53:20,922 - INFO - ttyACM0: PacketSend: {'token': 8}
    2021-07-05 03:53:20,940 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 8}}
    In [21]: ex.get()
    
    2021-07-05 03:53:26,660 - INFO - ttyACM0: PacketSend: {'token': 9}
    2021-07-05 03:53:26,693 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 9}}
    In [22]: ex.get()
    
    2021-07-05 03:53:30,217 - INFO - ttyACM0: PacketSend: {'token': 10}
    2021-07-05 03:53:30,242 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 10}}
    In [23]: ex.get()
    
    2021-07-05 03:53:35,963 - INFO - ttyACM0: PacketSend: {'token': 11}
    2021-07-05 03:53:35,995 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 11}}
    In [24]: ex.get()
    
    2021-07-05 03:53:40,663 - INFO - ttyACM0: PacketSend: {'token': 12}
    2021-07-05 03:53:40,683 - INFO - ttyACM0: {event: MeshTxComplete, data: {'token': 12}}
    2021-07-05 03:53:40,731 - INFO - ttyACM0.LightClient: Present value is off
    

  • Hi,

    Arif@Lynxemi said:
    I do note that sometimes I send one of these commands and I only get the first two lines, so I have to send the command again to receive all four lines. Is this normal?

    It is difficult to know, but my guess is that it be some issues with the serial communication.

    The problem is still that you get NRF_INVALID_PARAM from access_model_publish, but not when access_model_reply is being used. The problem maybe that the stack does not know the publication address. When access_model_reply is called it will use the return address, but when publication is done it need the publish appkey and address. You could add some debug before mesh/access/src/access.c l:318 (function check_tx_params) to check if publish_address_handle (and publish_appkey_handle) is set correct.

  • The problem is still that you get NRF_INVALID_PARAM from access_model_publish, but not when access_model_reply is being used. The problem maybe that the stack does not know the publication address.

    Oh right that does make sense. The reason I used publish instead of reply, is because when the set command is received by the server, it goes through a test function that results in a callback for access_model_publish. On the server device, there is also a hardware button that could trigger this test, so I thought access_model_reply wouldn't make sense for the same callback. 

    How then do I set the publication address for access_model_publish to work? I suppose I would have to get the publication address of the serial device running interactive_pyaci and use these two commands?

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

Related