matter_rgb.tc¶
Matter Smart Plug + RGB Color Light — pure TinyC on an ESP32-C6.
// Matter Smart Plug + RGB Color Light — pure TinyC on an ESP32-C6.
//
// Endpoint 1: On/Off plug -> relay 1 (set GPIO7 = Relay1 on the device)
// Endpoint 2: Color Light -> onboard WS2812 RGB LED on GPIO8 via rgbLed()
//
// The matter_c engine (firmware) does commissioning (SPAKE2+/PASE, CASE) and the
// Interaction Model. This script declares the two endpoints and turns Matter's
// On/Off + brightness (LevelControl) + colour (ColorControl Hue/Saturation) into
// an 0xRRGGBB value it pushes to the LED. Open pairing from the web /mt page
// (Bind), then control both devices from any Matter controller.
int plug_ep; // relay endpoint id
int rgb_ep; // colour-light endpoint id
int rgb_gpio; // WS2812 data pin (onboard RGB on the C6 = GPIO8)
int rgb_on; // light On/Off, tracked from the OnOff command
// HSV (each 0..254, the Matter range) -> packed 0xRRGGBB.
int hsv2rgb(int h, int s, int v) {
int region; int rem; int p; int q; int t; int r; int g; int b;
if (s == 0) { return (v << 16) + (v << 8) + v; } // unsaturated -> white/grey
region = (h * 6) / 255;
rem = (h * 6) - (region * 255);
p = (v * (255 - s)) / 255;
q = (v * (255 - (s * rem) / 255)) / 255;
t = (v * (255 - (s * (255 - rem)) / 255)) / 255;
r = v; g = t; b = p; // region 0
if (region == 1) { r = q; g = v; b = p; }
if (region == 2) { r = p; g = v; b = t; }
if (region == 3) { r = p; g = q; b = v; }
if (region == 4) { r = t; g = p; b = v; }
if (region == 5) { r = v; g = p; b = q; }
return (r << 16) + (g << 8) + b;
}
// Read the light's current Matter attributes and drive the LED.
void updateRGB() {
int lvl; int hue; int sat;
if (rgb_on == 0) { rgbLed(rgb_gpio, 0); return; }
lvl = matterGet(rgb_ep, CLUSTER_LEVEL, 0); // CurrentLevel 0..254 (brightness)
hue = matterGet(rgb_ep, 0x0300, 0); // ColorControl CurrentHue
sat = matterGet(rgb_ep, 0x0300, 1); // ColorControl CurrentSaturation
if (lvl < 1) { lvl = 254; } // full brightness if unset
rgbLed(rgb_gpio, hsv2rgb(hue, sat, lvl));
}
// A Matter controller invoked a command on one of our clusters. The engine has
// already applied LevelControl/ColorControl values to the attributes, so for the
// light we just re-read and refresh.
void MatterInvoke(int e, int cluster, int cmd) {
if (e == plug_ep) {
if (cluster == CLUSTER_ONOFF) {
if (cmd == 2) { tasm_power = 1 - tasmPower(0); } else { tasm_power = cmd; }
}
return;
}
if (e == rgb_ep) {
if (cluster == CLUSTER_ONOFF) {
if (cmd == 2) { rgb_on = 1 - rgb_on; } else { rgb_on = cmd; }
}
updateRGB();
}
}
int main() {
rgb_gpio = 8; // onboard WS2812 on the ESP32-C6 dev board
rgb_on = 0;
matterReset(); // clean data model (root node only)
// Endpoint 1 — On/Off plug -> relay 1 (GPIO7)
plug_ep = matterAdd(MATTER_PLUG);
matterName(plug_ep, "Plug"); // accessory title in the controller
// Endpoint 2 — Extended Color Light (device type 0x010D) -> RGB on GPIO8
rgb_ep = matterAdd(0x010D);
matterName(rgb_ep, "RGB Light"); // accessory title in the controller
matterCluster(rgb_ep, CLUSTER_ONOFF);
matterAttr(rgb_ep, CLUSTER_ONOFF, 0, MTR_BOOL); // OnOff
matterCluster(rgb_ep, CLUSTER_LEVEL);
matterAttr(rgb_ep, CLUSTER_LEVEL, 0, MTR_U8); // CurrentLevel
matterCluster(rgb_ep, 0x0300); // ColorControl
matterAttr(rgb_ep, 0x0300, 0, MTR_U8); // CurrentHue
matterAttr(rgb_ep, 0x0300, 1, MTR_U8); // CurrentSaturation
matterSet(rgb_ep, CLUSTER_LEVEL, 0, 254);
matterSet(rgb_ep, 0x0300, 0, 0);
matterSet(rgb_ep, 0x0300, 1, 0);
matterStart(); // Matter on (operational); press Bind on /mt to pair
rgbLed(rgb_gpio, 0); // LED off until paired + turned on
return 0;
}