Setting output expander counts via WebSocket

Is it currently possible to set output expander pixel counts over WebSockets? I know you can get the output expander values, but is it possible to send values back?

Thanks for the help!

Yes, it is possible. You can send the same binary expander configuration packets that you get from a “getConfig” websocket request. This feature isn’t in the current Python client because we didn’t have an immediate use case, but I’ll add it to the next version.

Here’s a quick and dirty test version that packs and sends an expander config packet based on the dictionary you get back from getConfigExpander() (which is in the current client.)

To use it, open a Pixelblaze object and create an expander config dictionary with config = pb.getConfigExpander(),
then modify it as necessary and call pb.setConfigExpander(config). (This probably isn’t perfect yet, but at least you can see how it’s supposed to work!)

    def setConfigExpander(self, config:dict):
        """Sets the OutputExpander configuration.

        Args:
            config (dict): A dictionary containing the configuration items, with settingName as the key and settingValue as the value.
        """
        # Convert the configuration to a binary blob.
        binaryData = self.__encodeExpanderData(config)

        # Send the configuration to the Pixelblaze.
        self.wsSendBinary(self.messageTypes.ExpanderConfig, binaryData, expectedResponse=None)

    # take the object returned by getExpanderConfig and convert it to a binary blob for sending to the Pixelblaze.
    def __encodeExpanderData(self, config:dict) -> bytes:
        """An internal function to convert the human-readable JSON representation of the OutputExpander into its native binary format.

        Args:
            config (dict): A human-readable dictionary of the configuration items.

        Returns:
            bytes: The binary OutputExpander blob to be sent to the Pixelblaze.
        """
        # check for valid expander version (TODO - need to support older protocol versions?  not really sure.)
        versionNumber = 5
        
        # Convert the file to a binary equivalent.
        binaryData = bytes([versionNumber])
        rowSize = 12

        colorOrders = {'RGB': 0x24, 'RBG': 0x18, 'BRG': 0x09, 'BGR': 0x06, 'GRB': 0x21, 'GBR': 0x12, 'RGBW': 0xE4, 'GRBW': 0xE1}              
        for board in config['expanders']:
            for row in range(8):
                if row in board['rows']:
                    rowConfig = board['rows'][row][0]
                    binaryData += struct.pack('<4B2H4x', (board['address'] << 3) + row, rowConfig['type'],3,colorOrders[rowConfig['options']], rowConfig['count'],rowConfig['startIndex'])
                else:
                    binaryData += struct.pack('<4B2H4x', (board['address'] << 3) + row, 0, 0, 0, 0, 0)

        # Return the finished configuration.
        return binaryData

3 Likes

Exactly what I needed, thanks so much!

1 Like

Quick note: I know you’re not using Python, but the mysterious ‘3’ in the output packet is actually the number of color channels – 3 for most LEDs, 4 for RGBW, etc. I hardwired it into the test function after discovering that getConfigExpander() doesn’t include it in the outgoing dictionary. It’ll be fixed in the next release.

2 Likes