Zigbee remote over MQTT
Reads the button presses of a Zigbee remote straight from Zigbee2MQTT, and turns a light on, off, brighter or dimmer. No Home Assistant automation is involved, and presses are handled as soon as they arrive.
You need Zigbee2MQTT and an MQTT server that Stewart is connected to.
<?php
declare(strict_types=1);
namespace App;
use Stewart\Contracts\App;use Stewart\Contracts\Automation;use Stewart\Contracts\HaContext;use Stewart\Contracts\Mqtt\Mqtt;use Stewart\Contracts\Mqtt\MqttMessage;use Stewart\Contracts\Service\ServiceTarget;
#[Automation(id: 'zigbee-remote')]final readonly class ZigbeeRemote implements App{ public function __construct( private HaContext $ha, private Mqtt $mqtt, private string $remote = 'living_room_remote', private string $light = 'light.living_room', ) {}
public function initialize(): void { $this->mqtt->watchMessages("zigbee2mqtt/{$this->remote}/action")->subscribe(function (MqttMessage $message): void { [$service, $data] = match ($message->payload) { 'on' => ['turn_on', []], 'off' => ['turn_off', []], 'brightness_up' => ['turn_on', ['brightness_step_pct' => 10]], 'brightness_down' => ['turn_on', ['brightness_step_pct' => -10]], default => [null, []], };
if ($service !== null) { $this->ha->callService('light', $service, $data, ServiceTarget::forEntities($this->light)); } }); }
public function dispose(): void {}}apps: zigbee-remote: options: remote: living_room_remote # the remote's friendly name in Zigbee2MQTT light: light.living_roomHow it works
Section titled “How it works”- Zigbee2MQTT publishes each press on
zigbee2mqtt/<name>/action, with the action as the payload. - A
matchturns each action into a service and its data. Unknown actions are ignored. brightness_step_pctchanges the brightness relative to where it is.
<?php
declare(strict_types=1);
namespace App\Tests;
use App\ZigbeeRemote;use PHPUnit\Framework\TestCase;use Stewart\Contracts\Mqtt\MqttMessage;use Stewart\Testing\App\AppHarness;
final class ZigbeeRemoteTest extends TestCase{ private AppHarness $harness;
protected function setUp(): void { $this->harness = new AppHarness(); $this->harness->startApp(ZigbeeRemote::class); }
public function testBrightnessUpBrightensTheLight(): void { $this->harness->mqtt->pushMessage(new MqttMessage('zigbee2mqtt/living_room_remote/action', 'brightness_up'));
$call = $this->harness->ha->getLastCall(); self::assertSame('light.turn_on', $call->getServiceName()); self::assertSame(['brightness_step_pct' => 10], $call->data); }
public function testUnknownActionsAreIgnored(): void { $this->harness->mqtt->pushMessage(new MqttMessage('zigbee2mqtt/living_room_remote/action', 'arrow_left_click'));
self::assertTrue($this->harness->ha->calls->isEmpty()); }}Make it yours
Section titled “Make it yours”- Find your remote’s actions: watch
zigbee2mqtt/<name>/actionwithmosquitto_sub, and press each button. - Long presses: many remotes send
brightness_move_upandbrightness_stop; start arunEvery()on the first and cancel it on the second.