RGB565 Color Space (mainly for SPI TFT screens)

#RGB565 #RGB888 #RGB mqtt #M5Stick #ESP32 gpio #colorpicker

I've got a couple of M5StickC-Plus devices
image

and have them working with the NodeRED aedes MQTT broker, using JSON payloads.

example :-
{"LED":true,"LEDrate":200,"beep":true,"beepPitch":2000,"bgColour":-1,"colour":-2,"screen":2,"message":"Hello World","SerialDebug":false,"encLED":0xff0000}

From there I can read the status of both button, adapt the screen content, set the LED and Beep.

I've even included the ability to use

image

  • M5-MiniEncoder
    Encoder count,
    Encoder step value,
    Encoder direction,
    Encoder button status
    Setting Encoder LED RGB888 (on the rear on the unit)
    Clearing Encoder counter

image

  • M5.8Encoder
    Read each Encoder counter
    Read each Encoder button status
    Read Encoder Switch status
    Set ALL Encoder LED (RGB888)
    Set one-by-one Encoder LED (RGB888)
    Clear all Encoder counters

image

image

As an example - Two buttons for Grove port
Any volt free contact closure will work across 0v and GPio pin/s

  • Status' of both (Bottom Grove port) GPIO pins (Pin32 & Pin33) for contact closures

Initially to set the BackGround and Text colours, I simply sent a value between -1 and -9 as an INT and a couple of IF statements to map to a few of the pre-defined colour options.

However what I really wanted was to be able to use a colour picker to set them.

The problem is that while the LED components use RGB888 format values, the TFT screen uses RGB565.

I searched for days and days trying to find a simple function node to bit shift the RGB values to a limited RGB565 format.

Eventually I relented and set about doing it the long way with BitUnloader

(I have also used "Color Convertor" in this flow, so that I can use other color spaces)

Until there is a cleaner / nicer way of doing it, here is my flow.

I am happy to share the MQTT flow and Arduino Script for the M5StickC-Plus if anyone is interested

[
    {
        "id": "4da8de9fdd60e66e",
        "type": "tab",
        "label": "RGB565",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "1a98fa35b22665a0",
        "type": "junction",
        "z": "4da8de9fdd60e66e",
        "x": 480,
        "y": 580,
        "wires": [
            [
                "9035c16838ab2c79",
                "adbc20cedcabb262"
            ]
        ]
    },
    {
        "id": "86c3851afdf9d02a",
        "type": "ui_colour_picker",
        "z": "4da8de9fdd60e66e",
        "name": "RGB Colour Picker Object",
        "label": "RGB BG Colour",
        "group": "c61238e556dd18bf",
        "format": "rgb",
        "outformat": "object",
        "showSwatch": true,
        "showPicker": true,
        "showValue": true,
        "showHue": false,
        "showAlpha": false,
        "showLightness": true,
        "square": "false",
        "dynOutput": "false",
        "order": 1,
        "width": 6,
        "height": 6,
        "passthru": true,
        "topic": "bgColour",
        "topicType": "str",
        "className": "",
        "x": 250,
        "y": 560,
        "wires": [
            [
                "1a98fa35b22665a0"
            ]
        ]
    },
    {
        "id": "cef5b2826321ccf3",
        "type": "ui_text",
        "z": "4da8de9fdd60e66e",
        "group": "c61238e556dd18bf",
        "order": 4,
        "width": 0,
        "height": 0,
        "name": "RGB565",
        "label": "RGB565",
        "format": "{{msg.payload}}",
        "layout": "col-center",
        "className": "",
        "style": true,
        "font": "Arial Black,Arial Black,Gadget,sans-serif",
        "fontSize": "22",
        "color": "#ff0a0a",
        "x": 1060,
        "y": 880,
        "wires": []
    },
    {
        "id": "998bd22810febe07",
        "type": "ui_text",
        "z": "4da8de9fdd60e66e",
        "group": "c61238e556dd18bf",
        "order": 3,
        "width": 0,
        "height": 0,
        "name": "RGB888",
        "label": "RGB888",
        "format": "{{msg.payload.hex}}",
        "layout": "col-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": 16,
        "color": "#000000",
        "x": 1280,
        "y": 540,
        "wires": []
    },
    {
        "id": "e8ccee752e20537b",
        "type": "bitunloader",
        "z": "4da8de9fdd60e66e",
        "name": "unload payload.r",
        "mode": "objectBits",
        "prop": "payload.r",
        "padding": "8",
        "x": 570,
        "y": 800,
        "wires": [
            [
                "8b56bf71bf74ef41"
            ]
        ]
    },
    {
        "id": "f7366b256e95d4cf",
        "type": "debug",
        "z": "4da8de9fdd60e66e",
        "name": "Unloaded Bits",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "RGB",
        "statusType": "msg",
        "x": 1300,
        "y": 800,
        "wires": []
    },
    {
        "id": "adbc20cedcabb262",
        "type": "function",
        "z": "4da8de9fdd60e66e",
        "name": "Store RGB",
        "func": "msg.RGB = {           \n        \"red\": msg.payload.r,\n        \"green\": msg.payload.g,\n        \"blue\": msg.payload.b\n      };\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 230,
        "y": 800,
        "wires": [
            [
                "e8ccee752e20537b"
            ]
        ]
    },
    {
        "id": "8b56bf71bf74ef41",
        "type": "bitunloader",
        "z": "4da8de9fdd60e66e",
        "name": "unload payload.g",
        "mode": "objectBits",
        "prop": "payload.g",
        "padding": "8",
        "x": 810,
        "y": 800,
        "wires": [
            [
                "cf9de4e93d336edc"
            ]
        ]
    },
    {
        "id": "cf9de4e93d336edc",
        "type": "bitunloader",
        "z": "4da8de9fdd60e66e",
        "name": "unload payload.b",
        "mode": "objectBits",
        "prop": "payload.b",
        "padding": "8",
        "x": 1030,
        "y": 800,
        "wires": [
            [
                "f7366b256e95d4cf",
                "6890979584dd07d9"
            ]
        ]
    },
    {
        "id": "9c5ef762650188f6",
        "type": "bitreloader",
        "z": "4da8de9fdd60e66e",
        "name": "",
        "autoMode": "manual",
        "prop": "RGB565",
        "mode": "arrayBits",
        "x": 550,
        "y": 880,
        "wires": [
            [
                "bfaa666c199d30f5",
                "f6540d7669422884"
            ]
        ]
    },
    {
        "id": "6890979584dd07d9",
        "type": "function",
        "z": "4da8de9fdd60e66e",
        "name": "Shift RGB BITS",
        "func": "\n\nmsg.RGB565_bits = [];\n\n\n// 5 high bits from RED\nmsg.RGB565_bits[15] = msg.payload.r.b7;\nmsg.RGB565_bits[14] = msg.payload.r.b6;\nmsg.RGB565_bits[13] = msg.payload.r.b5;\nmsg.RGB565_bits[12] = msg.payload.r.b4;\nmsg.RGB565_bits[11] = msg.payload.r.b3;\n\n// 6 high bits from GREEN\nmsg.RGB565_bits[10] = msg.payload.g.b7;\nmsg.RGB565_bits[9]  = msg.payload.g.b6;\nmsg.RGB565_bits[8]  = msg.payload.g.b5;\nmsg.RGB565_bits[7]  = msg.payload.g.b4;\nmsg.RGB565_bits[6]  = msg.payload.g.b3;\nmsg.RGB565_bits[5]  = msg.payload.g.b2;\n\n\n// 5 high bits from Blue\nmsg.RGB565_bits[4] = msg.payload.b.b7;\nmsg.RGB565_bits[3] = msg.payload.b.b6;\nmsg.RGB565_bits[2] = msg.payload.b.b5;\nmsg.RGB565_bits[1] = msg.payload.b.b4;\nmsg.RGB565_bits[0] = msg.payload.b.b3;\n\nmsg.RGB565 = [];\n\nmsg.RGB565 = msg.RGB565_bits;\n\nreturn msg;\n\n\n// Based on this notation\n// rgb565 = ((rgb888.r & 0xf80000) >> 8) | ((rgb888.g & 0xfc00) >> 5) | ((rgb888.b & 0xf8) >> 3);\n//\n// See \n// http://www.barth-dev.de/about-rgb565-and-how-to-convert-into-it/",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 240,
        "y": 880,
        "wires": [
            [
                "9c5ef762650188f6"
            ]
        ]
    },
    {
        "id": "551c0914dfa614ae",
        "type": "node-red-contrib-colorspace",
        "z": "4da8de9fdd60e66e",
        "name": "Convert",
        "target": "payload",
        "x": 1040,
        "y": 540,
        "wires": [
            [
                "a0c35899dc6b01b0",
                "998bd22810febe07"
            ]
        ]
    },
    {
        "id": "9035c16838ab2c79",
        "type": "function",
        "z": "4da8de9fdd60e66e",
        "name": "Rearrange payload",
        "func": "// Take an RGB component payload and arrange it ready for Color Convertor to use\n// review the Debug output for results\n\n\nmsg =      {\n         \"payload\":{\n             \"rgb\": {\n                 \"red\": msg.payload.r,\n                 \"green\": msg.payload.g,\n                 \"blue\": msg.payload.b\n             }\n         }\n     }\nreturn msg;\n\n// Use a section of the following to make use of different colour spaces.\n\n//      How to use\n//      You can send in the payload one of the types supported\n//      \n//      You can send\n//      \n//      RGB\n//      \n// msg =     {\n//          \"payload\":{\n//              \"rgb\": {\n//                  \"red\": 255,\n//                  \"green\": 10,\n//                  \"blue\": 20\n//              }\n//          }\n//      };\n\n\n\n\n//      HSV\n//      \n//  msg =    {\n//          \"payload\":{\n//              \"hsv\": {\n//                  \"hue\": 358,\n//                  \"staturation\": 96,\n//                  \"brightness\": 100\n//              }\n//          }\n//      };\n\n\n\n\n//      HSL\n//      \n// msg =      {\n//          \"payload\":{\n//              \"hsl\": {\n//                  \"hue\": 358,\n//                  \"staturation\": 96,\n//                  \"lightness\": 52\n//              }\n//          }\n//      };\n\n\n\n\n//      HWB\n//      \n// msg =     {\n//          \"payload\":{\n//              \"hwb\": {\n//                  \"hue\": 358,\n//                  \"whiteness\": 4,\n//                  \"blackness\": 0\n//              }\n//          }\n//      };\n\n\n//      CMYK\n//      \n//msg =      {\n//          \"payload\":{\n//              \"cmyk\": {\n//                  \"cyan\": 0,\n//                  \"magenta\": 96,\n//                  \"yellow\": 92,\n//                  \"black\": 0\n//              }\n//          }\n//      };\n\n\n//      XYZ\n//      \n// msg =     {\n//          \"payload\":{\n//              \"xyz\": {\n//                  \"x\": 41,\n//                  \"y\": 22,\n//                  \"z\": 3\n//              }\n//          }\n//      };\n\n\n//      HEX\n//      \n// msg =     {\n//          \"payload\":{\n//              \"hex\": \"FF0A14\"\n//          }\n//      };\n\n\n\n//      Temperature\n//      \n// msg =     {\n//          \"payload\":{\n//              \"temperatute\": 5000\n//          }\n//      };\n\n\n//      Keyword\n//      \n// msg =     {\n//          \"payload\":{\n//              \"keyword\": \"red\"\n//          }\n//      };\n\n\n//      Direct Color Name in Payload\n//      \n// msg =      {\n//          \"payload\": \"red\"\n//      };\n\n\n\n\n//      Direct Color Temperature Name in Payload\n//      \n// msg =      {\n//          \"payload\": \"daylight\"\n//      };     ",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 850,
        "y": 540,
        "wires": [
            [
                "551c0914dfa614ae"
            ]
        ]
    },
    {
        "id": "a0c35899dc6b01b0",
        "type": "debug",
        "z": "4da8de9fdd60e66e",
        "name": "Color Converter as HEX RGB888",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload.hex",
        "statusType": "msg",
        "x": 1320,
        "y": 460,
        "wires": []
    },
    {
        "id": "bfaa666c199d30f5",
        "type": "function",
        "z": "4da8de9fdd60e66e",
        "name": "Convert to String",
        "func": "var RGB565_HEX = \"0x\"+msg.RGB565.toString(16);\nvar RGB565_NUM = msg.RGB565;\nvar NEWmsg = {}; // create a fresh MESSAGE\n\nNEWmsg.payload = RGB565_HEX;\nNEWmsg.RGB565_HEX = RGB565_HEX;\nNEWmsg.RGB565_NUM = RGB565_NUM;\n\nNEWmsg.topic = msg.topic; // retain orginal Topic from colour picker\n\nreturn NEWmsg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 810,
        "y": 880,
        "wires": [
            [
                "c8b371f3f14c965a",
                "cef5b2826321ccf3",
                "a57ca1ff064c4345",
                "08df3bdc8f9f8d7c"
            ]
        ]
    },
    {
        "id": "f6540d7669422884",
        "type": "debug",
        "z": "4da8de9fdd60e66e",
        "name": "Reloaded",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "RGB565",
        "statusType": "msg",
        "x": 560,
        "y": 960,
        "wires": []
    },
    {
        "id": "c8b371f3f14c965a",
        "type": "debug",
        "z": "4da8de9fdd60e66e",
        "name": "RGB565 As String",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "msg",
        "x": 1070,
        "y": 940,
        "wires": []
    },
    {
        "id": "cdc5baf363c5538e",
        "type": "comment",
        "z": "4da8de9fdd60e66e",
        "name": "This Flow Uses ---",
        "info": "BitUnloader - \nnode-red-contrib-bitunloader\n\nhttps://flows.nodered.org/node/node-red-contrib-bitunloader\n\nFor converting from any other Colour Space format, this Node pallette\n\nColor Converter\nnode-red-contrib-colorspace\n\nhttps://flows.nodered.org/node/node-red-contrib-colorspace\n\nSee the \"Rearrange Payload\" function mode for examples of how use different colour spaces",
        "x": 630,
        "y": 420,
        "wires": []
    },
    {
        "id": "a57ca1ff064c4345",
        "type": "ui_text",
        "z": "4da8de9fdd60e66e",
        "group": "c61238e556dd18bf",
        "order": 3,
        "width": 0,
        "height": 0,
        "name": "Colour picker topic",
        "label": "msg.topic",
        "format": "{{msg.topic}}",
        "layout": "col-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": 16,
        "color": "#000000",
        "x": 1290,
        "y": 880,
        "wires": []
    },
    {
        "id": "8587bcb73ac642b1",
        "type": "link out",
        "z": "4da8de9fdd60e66e",
        "name": "RGB565",
        "mode": "link",
        "links": [
            "1e398a0e5223f471"
        ],
        "x": 1085,
        "y": 1100,
        "wires": []
    },
    {
        "id": "20f0d86d6e039f26",
        "type": "ui_colour_picker",
        "z": "4da8de9fdd60e66e",
        "name": "RGB Colour Picker Object",
        "label": "RGB Colour (Text)",
        "group": "c61238e556dd18bf",
        "format": "rgb",
        "outformat": "object",
        "showSwatch": true,
        "showPicker": true,
        "showValue": true,
        "showHue": false,
        "showAlpha": false,
        "showLightness": true,
        "square": "false",
        "dynOutput": "false",
        "order": 1,
        "width": 6,
        "height": 6,
        "passthru": true,
        "topic": "colour",
        "topicType": "str",
        "className": "",
        "x": 250,
        "y": 520,
        "wires": [
            [
                "1a98fa35b22665a0"
            ]
        ]
    },
    {
        "id": "08df3bdc8f9f8d7c",
        "type": "change",
        "z": "4da8de9fdd60e66e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "RGB565_NUM",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 960,
        "y": 1020,
        "wires": [
            [
                "8587bcb73ac642b1"
            ]
        ]
    },
    {
        "id": "eb584f5bb0c818e3",
        "type": "inject",
        "z": "4da8de9fdd60e66e",
        "name": "RED bgColour",
        "props": [
            {
                "p": "payload.r",
                "v": "255",
                "vt": "num"
            },
            {
                "p": "payload.g",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "payload.b",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "bgColour",
        "x": 250,
        "y": 620,
        "wires": [
            [
                "1a98fa35b22665a0"
            ]
        ]
    },
    {
        "id": "d2153bb8e48b6806",
        "type": "inject",
        "z": "4da8de9fdd60e66e",
        "name": "Green bgColour",
        "props": [
            {
                "p": "payload.r",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "payload.g",
                "v": "255",
                "vt": "num"
            },
            {
                "p": "payload.b",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "bgColour",
        "x": 260,
        "y": 660,
        "wires": [
            [
                "1a98fa35b22665a0"
            ]
        ]
    },
    {
        "id": "241e6c15ed74d629",
        "type": "inject",
        "z": "4da8de9fdd60e66e",
        "name": "Blue bgColour",
        "props": [
            {
                "p": "payload.r",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "payload.g",
                "v": "0",
                "vt": "num"
            },
            {
                "p": "payload.b",
                "v": "255",
                "vt": "num"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "bgColour",
        "x": 270,
        "y": 700,
        "wires": [
            [
                "1a98fa35b22665a0"
            ]
        ]
    },
    {
        "id": "14da255eb653f239",
        "type": "ui_spacer",
        "z": "4da8de9fdd60e66e",
        "name": "spacer",
        "group": "c61238e556dd18bf",
        "order": 2,
        "width": 6,
        "height": 1
    },
    {
        "id": "c61238e556dd18bf",
        "type": "ui_group",
        "name": "RGB888 to RGB565",
        "tab": "e1ff5a2631fc1f9b",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": true,
        "className": ""
    },
    {
        "id": "e1ff5a2631fc1f9b",
        "type": "ui_tab",
        "name": "RGB565",
        "icon": "dashboard",
        "order": 3,
        "disabled": false,
        "hidden": false
    }
]