prettyprint

2023年2月7日 星期二

[Raspberry Pi Pico W (c-sdk)] lwIP: Ep 4. MQTT Client & Node-RED & Mosquitto & WS2812

 本文章介紹Raspberry Pi Pico W 使用lwIP MQTT Client 透過手機設定Pico W 上的WS2812 LED燈條展示方式。

  1. 顯示時鐘。
  2. 警示閃光。
  3. 隨機顏色、燈數與方向。
  4. 固定顏色、燈數與方向。




一、pico-sdk加入MQTT library:

pico-sdk(1.4)未將lwip MQTT client application llibrary加入,為了使用lwIP MQTT Client library修正下列檔案加入MQTT Client library。

(註:Pico SDK 1.5.0 已經加入了)

pico-sdk/src/rp2-common/pico_lwip/CMakeLists.txt:

#MQTT 

    add_library(pico_lwip_mqtt INTERFACE)
    target_sources(pico_lwip_mqtt INTERFACE
            ${PICO_LWIP_PATH}/src/apps/mqtt/mqtt.c
            )

如下圖所示:

在project CMakeLists.txt加入pico_lwip_mqtt library。


二、WS2812 LED燈條:

根據Datasheet每個bit 0 & 1 timer,使用raspberry Pi Pico PIO的時間如下圖:

WS2812的  Send data at speeds of 800Kbps. PIO clock如下設定。

ws2812_program_init(pio, sm, WS2812_PIN, 800000);


三、lwIP MQTT Clinet Appliction:
Subscribe API:
    mqtt_sub_unsub(): subscribe or unsubscribe MQTT topic。
    mqtt_set_inpub_callback():設定callback function,接收subscribe的topic&message。
    mqtt_incoming_publish_cb_t: callback function 接收topic 與total length。
    mqtt_incoming_data_cb_t: callback funcion 接收subscibe data。
Publish API:
    mqtt_publish(): publish a topic message。
Connection API:
    mqtt_client_connect(): connect to MQTT server。設定connected callback。
    mqtt_connection_cb_t: connect callback function,mqtt_connection_status_t 參數為連線狀態。

四、MQTT Server & Node-RED

    請參閱下列連結進一步說明:



五、成果影片:




六、程式碼:

  • Pi Pico W
 #include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "pico/cyw43_arch.h"
#include "hardware/rtc.h"

#include "lwip/apps/mqtt.h"
#include "ws2812.pio.h"
#include "hardware/clocks.h"
#include "ntp_time.h"
#include "cJSON.h"

#define WIFI_SSID "your_SSID"
#define WIFI_PASSWORD "your_PASSWORD"

typedef struct MQTT_CLIENT_DATA_T_ {
    mqtt_client_t* mqtt_client_inst;
    struct mqtt_connect_client_info_t mqtt_client_info;
    uint8_t data[MQTT_OUTPUT_RINGBUF_SIZE];
    uint8_t topic[100];
    uint32_t len;
    bool playing;
    bool newTopic;
} MQTT_CLIENT_DATA_T;

MQTT_CLIENT_DATA_T *mqtt;

struct mqtt_connect_client_info_t mqtt_client_info=
{
  "ws2812",
  NULL, /* user */
  NULL, /* pass */
  0,  /* keep alive */
  NULL, /* will_topic */
  NULL, /* will_msg */
  0,    /* will_qos */
  0     /* will_retain */
#if LWIP_ALTCP && LWIP_ALTCP_TLS
  , NULL
#endif
};

#define NUM_PIXELS 60
#define WS2812_PIN 16

#define green 0xff0000
#define red 0x00ff00
#define blue 0x0000ff
uint32_t color_pixel[NUM_PIXELS];
repeating_timer_t colok_timer;

static inline void ws2812_program_init(PIO pio, uint sm, uint pin, float freq) {
    pio_gpio_init(pio, pin);
    pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);

    uint offset = pio_add_program(pio, &ws2812_program);

    pio_sm_config c = ws2812_program_get_default_config(offset);
    sm_config_set_sideset_pins(&c, pin);
    sm_config_set_out_shift(&c, false, true, 24);
    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);

    int cycles_per_bit = ws2812_T1 + ws2812_T2 *2;
    float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
    sm_config_set_clkdiv(&c, div);

    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}

static inline void put_pixel(uint32_t pixel_grb) {
    pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
}

static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
    return
            ((uint32_t) (r) << 8) |
            ((uint32_t) (g) << 16) |
            (uint32_t) (b);
}

void wait_connecting() {
    for (int i = 0; i < NUM_PIXELS; i++) put_pixel(red);
}

void clear_pixel() {
    for (int i = 0; i < NUM_PIXELS; i++) put_pixel(0x000000);
}

void connected() {
    for (int i = 0; i < NUM_PIXELS; i++) put_pixel(green);
}

void random_pixel(uint8_t color_index, uint len,  int dir, uint32_t color, uint8_t speed) {
    static uint t=0;

    while(mqtt->playing) { 
        if (len > NUM_PIXELS) len = NUM_PIXELS;
            for (int i=0; i < NUM_PIXELS; i++) color_pixel[i] = 0x000000;  // reset all pixel

            for (int i = t; i < (t+len);++i) {
                switch (color_index) {
                    case 1:
                    color_pixel[(i)%NUM_PIXELS]=color;
                    break;
                    case 2:
                    color_pixel[(i)%NUM_PIXELS] = (rand());
                    break;
                }
            }
            
        for (int i = 0; i < NUM_PIXELS; i++) put_pixel(color_pixel[i]);
        t = (t+dir+NUM_PIXELS) % NUM_PIXELS;
        sleep_ms(10*speed);
    }
    clear_pixel();
}

bool repeat_timer_cb(repeating_timer_t *rt) {
    static datetime_t dt;
  
    rtc_get_datetime(&dt);

    for (int i=0; i < NUM_PIXELS; i++) color_pixel[i]=0x000000;
    color_pixel[(dt.hour%12)*5] |= green;
    color_pixel[dt.min] |= blue;
    color_pixel[dt.sec] |= red;
    
    for (int i=0; i < NUM_PIXELS; i++) put_pixel(color_pixel[i]);
      
    return true;
}

void sparkle() {

      while(mqtt->playing) {
          for (int i = 0; i < NUM_PIXELS; ++i)
              put_pixel(rand() % 32 ? 0 : 0xffffffff);
          sleep_ms(10);
      }

}

void ws2812_action() {
    
    cancel_repeating_timer(&colok_timer);
    cJSON* json_obj = cJSON_CreateObject();
    json_obj = cJSON_Parse(mqtt->data);
    uint8_t *type = cJSON_GetStringValue(cJSON_GetObjectItem(json_obj, "type"));
    uint8_t speed = 11-(uint8_t)cJSON_GetNumberValue(cJSON_GetObjectItem(json_obj, "speed"));
    uint8_t length = (uint8_t)cJSON_GetNumberValue(cJSON_GetObjectItem(json_obj, "length"));
    int8_t dir = (int8_t)cJSON_GetNumberValue(cJSON_GetObjectItem(json_obj, "dir"));
    uint8_t *colorstr = (cJSON_GetStringValue(cJSON_GetObjectItem(json_obj, "color")));
    uint32_t color=strtoul(colorstr,NULL, 16);
  
    color = (color&0xff0000) >> 8 | (color&0x00ff00) << 8 | color &0x0000ff;

    if (strcmp(type, "clock") == 0) {
        mqtt->playing=true;
        add_repeating_timer_ms(-1000, repeat_timer_cb, NULL, &colok_timer);
    }
    if (strcmp(type, "sparkle") == 0) {
        mqtt->playing=true;
        sparkle();
    }
    if (strcmp(type, "randomcolor") == 0) {
        mqtt->playing=true;
        random_pixel(2,length,dir,0x000000,speed);////
    }
    if (strcmp(type, "pixelcolor") == 0) {
       mqtt->playing=true;
       random_pixel(1,length,dir,color,speed);////
    }
    cJSON_Delete(json_obj); 
}
void ws2812_stop() {
  mqtt->playing=false;
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) {
    MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
    LWIP_UNUSED_ARG(data);

    strncpy(mqtt_client->data, data, len);
    mqtt_client->len=len;
    mqtt_client->data[len]='\0';
    
    mqtt_client->newTopic=true;
    mqtt->playing=false;
 
}

static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) {
  MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
  strcpy(mqtt_client->topic, topic);
}

static void mqtt_request_cb(void *arg, err_t err) {
  MQTT_CLIENT_DATA_T* mqtt_client = ( MQTT_CLIENT_DATA_T*)arg;

  LWIP_PLATFORM_DIAG(("MQTT client \"%s\" request cb: err %d\n", mqtt_client->mqtt_client_info.client_id, (int)err));
}

static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) {
  MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
  LWIP_UNUSED_ARG(client);

  LWIP_PLATFORM_DIAG(("MQTT client \"%s\" connection cb: status %d\n", mqtt_client->mqtt_client_info.client_id, (int)status));

  if (status == MQTT_CONNECT_ACCEPTED) {
    mqtt_sub_unsub(client,
            "start", 0,
            mqtt_request_cb, arg,
            1);
    mqtt_sub_unsub(client,
            "stop", 0,
            mqtt_request_cb, arg,
            1);
  }
}

int main()
{
    stdio_init_all();
     PIO pio = pio0;
    int sm = 0;
    ws2812_program_init(pio, sm,  WS2812_PIN, 800000);

    mqtt=(MQTT_CLIENT_DATA_T*)calloc(1, sizeof(MQTT_CLIENT_DATA_T));

    if (!mqtt) {
        printf("mqtt client instant ini error\n");
        return 0;
    }
    mqtt->playing=false;
    mqtt->newTopic=false;
    mqtt->mqtt_client_info = mqtt_client_info;

    if (cyw43_arch_init())
    {
        printf("failed to initialise\n");
        return 1;
    }
    wait_connecting();
    cyw43_arch_enable_sta_mode();
    if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000))
    {
        printf("failed to connect\n");
        return 1;
    }
    ntp_time_init();
    get_ntp_time();
    ip_addr_t addr;
    if (!ip4addr_aton("your_MQTT_SERVER_IP", &addr)) {
        printf("ip error\n");
        return 0;
    }

   
    mqtt->mqtt_client_inst = mqtt_client_new();
    mqtt_set_inpub_callback(mqtt->mqtt_client_inst, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, mqtt);

    err_t err = mqtt_client_connect(mqtt->mqtt_client_inst, &addr, MQTT_PORT, &mqtt_connection_cb, mqtt, &mqtt->mqtt_client_info);
    if (err != ERR_OK) {
      printf("connect error\n");
      return 0;
    }
    connected();


    while(1) {
      if (mqtt->newTopic) { 
          mqtt->newTopic=false;
          if (strcmp(mqtt->topic, "start")==0) {
            ws2812_action();
          }
          if (strcmp(mqtt->topic, "stop")==0) {
              ws2812_stop();
          }
      }

   }
    return 0;
}

  • Node-RED flow
 [
    {
        "id": "6e21089b48879905",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "27103af5cfb31338",
        "type": "function",
        "z": "6e21089b48879905",
        "name": "function 1",
        "func": "var newmsg={};\n\nif (msg.payload == \"clock\" || msg.payload == \"sparkle\") {\n    newmsg.payload = {\n        \"group\":\n        {\n            \"hide\": [\"WS2812_SCROOLCOLOR\", \"WS2812_SLIDEPARAM\"]\n        }\n    };\n} else {\n    if (msg.payload==\"pixelcolor\") {\n        newmsg.payload = {\n            \"group\":\n            {\n                \"show\": [\"WS2812_SCROOLCOLOR\",\"WS2812_SLIDEPARAM\"]\n            }\n        };\n    } else {\n        newmsg.payload = {\n            \"group\":\n            {\n                \"hide\": [\"WS2812_SCROOLCOLOR\"], \"show\":[\"WS2812_SLIDEPARAM\"]\n            }\n        };\n    }\n}\n\n\nreturn newmsg",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 320,
        "y": 40,
        "wires": [
            [
                "700d3dc46fdd7924"
            ]
        ]
    },
    {
        "id": "dbe22a0817d2347d",
        "type": "ui_dropdown",
        "z": "6e21089b48879905",
        "name": "",
        "label": "Dispaly Type:",
        "tooltip": "",
        "place": "Select option",
        "group": "82089b24e7a5068c",
        "order": 1,
        "width": 5,
        "height": 1,
        "passthru": false,
        "multiple": false,
        "options": [
            {
                "label": "Clock",
                "value": "clock",
                "type": "str"
            },
            {
                "label": "Sparkle",
                "value": "sparkle",
                "type": "str"
            },
            {
                "label": "Pixel Color",
                "value": "pixelcolor",
                "type": "str"
            },
            {
                "label": "Random Color",
                "value": "randomcolor",
                "type": "str"
            }
        ],
        "payload": "",
        "topic": "type",
        "topicType": "msg",
        "className": "",
        "x": 120,
        "y": 80,
        "wires": [
            [
                "27103af5cfb31338",
                "1272075b2d61d0ce"
            ]
        ]
    },
    {
        "id": "700d3dc46fdd7924",
        "type": "ui_ui_control",
        "z": "6e21089b48879905",
        "name": "",
        "events": "all",
        "x": 480,
        "y": 40,
        "wires": [
            []
        ]
    },
    {
        "id": "5a66ec42f68bd5aa",
        "type": "ui_slider",
        "z": "6e21089b48879905",
        "name": "",
        "label": "speed",
        "tooltip": "",
        "group": "f72a2a2a55f0b438",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "topic",
        "topicType": "msg",
        "min": "1",
        "max": 10,
        "step": 1,
        "className": "",
        "x": 90,
        "y": 220,
        "wires": [
            [
                "50b09b338cf91909"
            ]
        ]
    },
    {
        "id": "ca0b6363716ad933",
        "type": "ui_slider",
        "z": "6e21089b48879905",
        "name": "",
        "label": "Pixels#",
        "tooltip": "",
        "group": "f72a2a2a55f0b438",
        "order": 3,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "topic",
        "topicType": "msg",
        "min": "1",
        "max": "59",
        "step": 1,
        "className": "",
        "x": 100,
        "y": 180,
        "wires": [
            [
                "08d9446473a7a2f2"
            ]
        ]
    },
    {
        "id": "ddb42afe82963199",
        "type": "ui_colour_picker",
        "z": "6e21089b48879905",
        "name": "",
        "label": "",
        "group": "ff7916db92ed582e",
        "format": "hex",
        "outformat": "string",
        "showSwatch": true,
        "showPicker": false,
        "showValue": true,
        "showHue": false,
        "showAlpha": false,
        "showLightness": true,
        "square": "false",
        "dynOutput": "false",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": false,
        "topic": "topic",
        "topicType": "msg",
        "className": "",
        "x": 110,
        "y": 360,
        "wires": [
            [
                "586673b8704f4617"
            ]
        ]
    },
    {
        "id": "d5e936d54e6a819b",
        "type": "ui_text",
        "z": "6e21089b48879905",
        "group": "ff7916db92ed582e",
        "order": 1,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Pick Color",
        "format": "",
        "layout": "col-center",
        "className": "",
        "x": 110,
        "y": 320,
        "wires": []
    },
    {
        "id": "3a36f74e374bc0ab",
        "type": "ui_text",
        "z": "6e21089b48879905",
        "group": "f72a2a2a55f0b438",
        "order": 1,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Select the number of Pixels and speed",
        "format": "{{msg.payload}}",
        "layout": "col-center",
        "className": "",
        "x": 190,
        "y": 140,
        "wires": []
    },
    {
        "id": "50b09b338cf91909",
        "type": "change",
        "z": "6e21089b48879905",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "speed",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 270,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "08d9446473a7a2f2",
        "type": "change",
        "z": "6e21089b48879905",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "length",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 270,
        "y": 180,
        "wires": [
            []
        ]
    },
    {
        "id": "586673b8704f4617",
        "type": "change",
        "z": "6e21089b48879905",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "color",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 310,
        "y": 360,
        "wires": [
            []
        ]
    },
    {
        "id": "08a77a34f56dd819",
        "type": "ui_button",
        "z": "6e21089b48879905",
        "name": "",
        "group": "e5d38edfd552806e",
        "order": 1,
        "width": 2,
        "height": 1,
        "passthru": false,
        "label": "Start",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 90,
        "y": 420,
        "wires": [
            [
                "32bc237d4be9a18c"
            ]
        ]
    },
    {
        "id": "32bc237d4be9a18c",
        "type": "function",
        "z": "6e21089b48879905",
        "name": "function 2",
        "func": "msg.payload={};\nmsg.payload.type=flow.get(\"type\") || \"\";\nmsg.payload.speed = flow.get(\"speed\") || 1;\nmsg.payload.length = flow.get(\"length\") || 1;\nmsg.payload.color = flow.get('color') || 0x000000;\nmsg.payload.dir = flow.get(\"dir\") || 1;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 240,
        "y": 420,
        "wires": [
            [
                "03cebb9c7b1959d8"
            ]
        ]
    },
    {
        "id": "1272075b2d61d0ce",
        "type": "change",
        "z": "6e21089b48879905",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "type",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 330,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "d98476ae54d711de",
        "type": "ui_button",
        "z": "6e21089b48879905",
        "name": "",
        "group": "e5d38edfd552806e",
        "order": 2,
        "width": 2,
        "height": 1,
        "passthru": false,
        "label": "Stop",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 90,
        "y": 480,
        "wires": [
            [
                "f82aa1487c39a9cb"
            ]
        ]
    },
    {
        "id": "d84ae8a0e6a9e047",
        "type": "mqtt out",
        "z": "6e21089b48879905",
        "name": "",
        "topic": "",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "466c902492653c8c",
        "x": 590,
        "y": 480,
        "wires": []
    },
    {
        "id": "03cebb9c7b1959d8",
        "type": "json",
        "z": "6e21089b48879905",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 370,
        "y": 420,
        "wires": [
            [
                "f31a49d4d4727859"
            ]
        ]
    },
    {
        "id": "f82aa1487c39a9cb",
        "type": "function",
        "z": "6e21089b48879905",
        "name": "function 3",
        "func": "msg.topic=\"stop\";\nmsg.payload=\"stop\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 280,
        "y": 480,
        "wires": [
            [
                "d84ae8a0e6a9e047"
            ]
        ]
    },
    {
        "id": "f31a49d4d4727859",
        "type": "function",
        "z": "6e21089b48879905",
        "name": "function 4",
        "func": "msg.topic=\"start\";\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 520,
        "y": 420,
        "wires": [
            [
                "d84ae8a0e6a9e047"
            ]
        ]
    },
    {
        "id": "9edca29e76cc4a35",
        "type": "ui_dropdown",
        "z": "6e21089b48879905",
        "name": "",
        "label": "Direction",
        "tooltip": "",
        "place": "",
        "group": "f72a2a2a55f0b438",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": true,
        "multiple": false,
        "options": [
            {
                "label": "clockwise",
                "value": 1,
                "type": "num"
            },
            {
                "label": "counterclockwise",
                "value": "-1",
                "type": "str"
            }
        ],
        "payload": "",
        "topic": "topic",
        "topicType": "msg",
        "className": "",
        "x": 100,
        "y": 260,
        "wires": [
            [
                "ed2d4290fb55a4bc"
            ]
        ]
    },
    {
        "id": "ed2d4290fb55a4bc",
        "type": "change",
        "z": "6e21089b48879905",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "dir",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 270,
        "y": 260,
        "wires": [
            []
        ]
    },
    {
        "id": "104b1503d903372c",
        "type": "ui_spacer",
        "z": "6e21089b48879905",
        "name": "spacer",
        "group": "82089b24e7a5068c",
        "order": 2,
        "width": 1,
        "height": 1
    },
    {
        "id": "7783de4639450be7",
        "type": "ui_spacer",
        "z": "6e21089b48879905",
        "name": "spacer",
        "group": "e5d38edfd552806e",
        "order": 3,
        "width": 2,
        "height": 1
    },
    {
        "id": "82089b24e7a5068c",
        "type": "ui_group",
        "name": "Default",
        "tab": "8caf46a96fa73472",
        "order": 1,
        "disp": false,
        "width": 6,
        "collapse": false,
        "className": ""
    },
    {
        "id": "f72a2a2a55f0b438",
        "type": "ui_group",
        "name": "SLIDEPARAM",
        "tab": "8caf46a96fa73472",
        "order": 2,
        "disp": false,
        "width": "5",
        "collapse": false,
        "className": ""
    },
    {
        "id": "ff7916db92ed582e",
        "type": "ui_group",
        "name": "SCROOLCOLOR",
        "tab": "8caf46a96fa73472",
        "order": 3,
        "disp": false,
        "width": "5",
        "collapse": false,
        "className": ""
    },
    {
        "id": "e5d38edfd552806e",
        "type": "ui_group",
        "name": "Buttons",
        "tab": "8caf46a96fa73472",
        "order": 5,
        "disp": false,
        "width": 6,
        "collapse": false,
        "className": ""
    },
    {
        "id": "466c902492653c8c",
        "type": "mqtt-broker",
        "name": "mosquitto",
        "broker": "localhost",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": "",
        "credentials": {}
    },
    {
        "id": "8caf46a96fa73472",
        "type": "ui_tab",
        "name": "WS2812",
        "icon": "dashboard",
        "disabled": false,
        "hidden": true
    }
]





沒有留言:

張貼留言