Skip to content

Commit

Permalink
Add support for Home Assistant lights (#1014)
Browse files Browse the repository at this point in the history
* Add mDNS scan for HomeAssistant

* Add template for HomeAssistant led driver

* Define structures for Home Assistant integration

* Add web Wizard for HA integration

* Add lamps discovery & setup construction for the wizard

* Load HA driver config

* Implement HA light control driver

* Add more configuration options

* Final implementation inc. saving state

* Update schema-skydimo.json

* Support for Home Assistant lights
  • Loading branch information
awawa-dev authored Dec 14, 2024
1 parent 69e1f0e commit f1e847f
Show file tree
Hide file tree
Showing 18 changed files with 759 additions and 39 deletions.
2 changes: 1 addition & 1 deletion include/bonjour/DiscoveryRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
class DiscoveryRecord
{
public:
enum Service { Unknown = 0, HyperHDR, WLED, PhilipsHue, Pico, ESP32_S2, ESP, SerialPort, REFRESH_ALL };
enum Service { Unknown = 0, HyperHDR, WLED, PhilipsHue, HomeAssistant, Pico, ESP32_S2, ESP, SerialPort, REFRESH_ALL };

Service type;
QString hostName;
Expand Down
3 changes: 2 additions & 1 deletion include/bonjour/DiscoveryWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class DiscoveryWrapper : public QObject

public slots:
QList<DiscoveryRecord> getPhilipsHUE();
QList<DiscoveryRecord> getHomeAssistant();
QList<DiscoveryRecord> getWLED();
QList<DiscoveryRecord> getHyperHDRServices();
QList<DiscoveryRecord> getAllServices();
Expand All @@ -66,5 +67,5 @@ public slots:
void cleanUp(QList<DiscoveryRecord>& target);

// contains all current active service sessions
QList<DiscoveryRecord> _hyperhdrSessions, _wledDevices, _hueDevices, _espDevices, _picoDevices, _esp32s2Devices;
QList<DiscoveryRecord> _hyperhdrSessions, _wledDevices, _hueDevices, _homeAssistantDevices, _espDevices, _picoDevices, _esp32s2Devices;
};
68 changes: 68 additions & 0 deletions include/led-drivers/net/DriverNetHomeAssistant.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#ifndef PCH_ENABLED
#include <QJsonObject>
#include <QJsonArray>
#include <memory>
#include <list>
#endif

#include <led-drivers/LedDevice.h>
#include <led-drivers/net/ProviderRestApi.h>
#include <linalg.h>

class DriverNetHomeAssistant : public LedDevice
{
Q_OBJECT

struct HomeAssistantLamp;

struct HomeAssistantInstance
{
QString homeAssistantHost;
QString longLivedAccessToken;
int transition;
int constantBrightness;
bool restoreOriginalState;

std::list<HomeAssistantLamp> lamps;
};

struct HomeAssistantLamp
{
enum Mode { RGB = 0, HSV };

QString name;
Mode colorModel;

struct
{
int isPoweredOn = -1;
int brightness = -1;
QJsonArray color;
} orgState;
};

public:
explicit DriverNetHomeAssistant(const QJsonObject& deviceConfig);
static LedDevice* construct(const QJsonObject& deviceConfig);

QJsonObject discover(const QJsonObject& params) override;

protected:
bool powerOn() override;
bool powerOff() override;

private:
bool init(const QJsonObject& deviceConfig) override;
int write(const std::vector<ColorRgb>& ledValues) override;
bool powerOnOff(bool isOn);
bool saveStates();
void restoreStates();

HomeAssistantInstance _haInstance;

std::unique_ptr<ProviderRestApi> _restApi;

static bool isRegistered;
};
4 changes: 2 additions & 2 deletions sources/api/HyperAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ void HyperAPI::handleTunnel(const QJsonObject& message, const QString& command,
const QString& data = message["data"].toString().trimmed();
const QString& service = message["service"].toString().trimmed();

if (service == "hue")
if (service == "hue" || service == "home_assistant")
{
QUrl tempUrl("http://"+ip);
if ((path.indexOf("/clip/v2") != 0 && path.indexOf("/api") != 0) || ip.indexOf("/") >= 0)
Expand All @@ -1305,7 +1305,7 @@ void HyperAPI::handleTunnel(const QJsonObject& message, const QString& command,

ProviderRestApi provider;

QUrl url = QUrl((path.startsWith("/clip/v2") ? "https://" : "http://")+tempUrl.host()+path);
QUrl url = QUrl((path.startsWith("/clip/v2") ? "https://" : "http://")+tempUrl.host() + ((service == "home_assistant" && tempUrl.port() >= 0) ? ":" + QString::number(tempUrl.port()) : "") + path);

Debug(_log, "Tunnel request for: %s", QSTRING_CSTR(url.toString()));

Expand Down
2 changes: 1 addition & 1 deletion sources/api/JSONRPC_schema/schema-tunnel.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"service": {
"type" : "string",
"required" : true,
"enum" : ["hue"]
"enum" : ["hue", "home_assistant"]
},
"ip": {
"type" : "string",
Expand Down
6 changes: 4 additions & 2 deletions sources/bonjour/BonjourServiceHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ BonjourServiceHelper::BonjourServiceHelper(BonjourServiceRegister* parent, QStri
has_ipv6 = 0;
_scanService = (1 << DiscoveryRecord::Service::HyperHDR) |
(1 << DiscoveryRecord::Service::WLED) |
(1 << DiscoveryRecord::Service::PhilipsHue);
(1 << DiscoveryRecord::Service::PhilipsHue) |
(1 << DiscoveryRecord::Service::HomeAssistant);

_running = true;

Expand Down Expand Up @@ -506,7 +507,8 @@ int BonjourServiceHelper::service_mdns(QString hostname, QString serviceName, in
{
for (auto scanner :{ DiscoveryRecord::Service::HyperHDR,
DiscoveryRecord::Service::WLED,
DiscoveryRecord::Service::PhilipsHue })
DiscoveryRecord::Service::PhilipsHue,
DiscoveryRecord::Service::HomeAssistant })
{
if (_scanService & (1 << scanner))
{
Expand Down
3 changes: 3 additions & 0 deletions sources/bonjour/BonjourServiceRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void BonjourServiceRegister::requestToScanHandler(DiscoveryRecord::Service type)
case (DiscoveryRecord::Service::HyperHDR): _helper->_scanService |= (1 << DiscoveryRecord::Service::HyperHDR); break;
case (DiscoveryRecord::Service::WLED): _helper->_scanService |= (1 << DiscoveryRecord::Service::WLED); break;
case (DiscoveryRecord::Service::PhilipsHue): _helper->_scanService |= (1 << DiscoveryRecord::Service::PhilipsHue); break;
case (DiscoveryRecord::Service::HomeAssistant): _helper->_scanService |= (1 << DiscoveryRecord::Service::HomeAssistant); break;
default: break;
}
}
Expand All @@ -102,6 +103,8 @@ void BonjourServiceRegister::messageFromFriendHandler(bool isExists, QString mdn
type = DiscoveryRecord::Service::WLED;
else if (mdnsString.indexOf(DiscoveryRecord::getmDnsHeader(DiscoveryRecord::Service::PhilipsHue)) >= 0)
type = DiscoveryRecord::Service::PhilipsHue;
else if (mdnsString.indexOf(DiscoveryRecord::getmDnsHeader(DiscoveryRecord::Service::HomeAssistant)) >= 0)
type = DiscoveryRecord::Service::HomeAssistant;
else if (mdnsString.indexOf(DiscoveryRecord::getmDnsHeader(DiscoveryRecord::Service::HyperHDR)) >= 0)
type = DiscoveryRecord::Service::HyperHDR;

Expand Down
2 changes: 2 additions & 0 deletions sources/bonjour/DiscoveryRecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const QString DiscoveryRecord::getmDnsHeader(Service service)
switch (service)
{
case(Service::PhilipsHue): return QLatin1String("_hue._tcp"); break;
case(Service::HomeAssistant): return QLatin1String("_home-assistant._tcp"); break;
case(Service::WLED): return QLatin1String("_wled._tcp"); break;
case(Service::HyperHDR): return QLatin1String("_hyperhdr-http._tcp"); break;
default: return "SERVICE_UNKNOWN";
Expand All @@ -49,6 +50,7 @@ const QString DiscoveryRecord::getName(Service _type)
switch (_type)
{
case(Service::PhilipsHue): return "Hue bridge"; break;
case(Service::HomeAssistant): return "Home Assistant"; break;
case(Service::WLED): return "WLED"; break;
case(Service::HyperHDR): return "HyperHDR"; break;
case(Service::Pico): return "Pico/RP2040"; break;
Expand Down
15 changes: 14 additions & 1 deletion sources/bonjour/DiscoveryWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ QList<DiscoveryRecord> DiscoveryWrapper::getPhilipsHUE()
return _hueDevices;
}

QList<DiscoveryRecord> DiscoveryWrapper::getHomeAssistant()
{
cleanUp(_homeAssistantDevices);

emit GlobalSignals::getInstance()->SignalDiscoveryRequestToScan(DiscoveryRecord::Service::HomeAssistant);

return _homeAssistantDevices;
}

QList<DiscoveryRecord> DiscoveryWrapper::getWLED()
{
cleanUp(_wledDevices);
Expand All @@ -104,7 +113,7 @@ QList<DiscoveryRecord> DiscoveryWrapper::getHyperHDRServices()

QList<DiscoveryRecord> DiscoveryWrapper::getAllServices()
{
return _hyperhdrSessions + _esp32s2Devices + _espDevices + _hueDevices + _picoDevices + _wledDevices;
return _hyperhdrSessions + _esp32s2Devices + _espDevices + _hueDevices + _homeAssistantDevices + _picoDevices + _wledDevices;
}

void DiscoveryWrapper::requestServicesScan()
Expand All @@ -113,6 +122,8 @@ void DiscoveryWrapper::requestServicesScan()
emit GlobalSignals::getInstance()->SignalDiscoveryRequestToScan(DiscoveryRecord::Service::WLED);
cleanUp(_hueDevices);
emit GlobalSignals::getInstance()->SignalDiscoveryRequestToScan(DiscoveryRecord::Service::PhilipsHue);
cleanUp(_homeAssistantDevices);
emit GlobalSignals::getInstance()->SignalDiscoveryRequestToScan(DiscoveryRecord::Service::HomeAssistant);
cleanUp(_hyperhdrSessions);
emit GlobalSignals::getInstance()->SignalDiscoveryRequestToScan(DiscoveryRecord::Service::HyperHDR);

Expand Down Expand Up @@ -172,6 +183,8 @@ void DiscoveryWrapper::signalDiscoveryEventHandler(DiscoveryRecord message)
gotMessage(_wledDevices, message);
else if (message.type == DiscoveryRecord::Service::PhilipsHue)
gotMessage(_hueDevices, message);
else if (message.type == DiscoveryRecord::Service::HomeAssistant)
gotMessage(_homeAssistantDevices, message);
else if (message.type == DiscoveryRecord::Service::Pico)
gotMessage(_picoDevices, message);
else if (message.type == DiscoveryRecord::Service::ESP32_S2)
Expand Down
1 change: 1 addition & 0 deletions sources/led-drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ add_library(led-drivers OBJECT ${Leddevice_SOURCES} )
target_link_libraries(led-drivers
Qt${Qt_VERSION}::Core
Qt${Qt_VERSION}::Network
linalg
)

IF ( HAVE_SERIAL_LED )
Expand Down
1 change: 1 addition & 0 deletions sources/led-drivers/LedDeviceSchemas.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@
<file alias="schema-yeelight">schemas/schema-yeelight.json</file>
<file alias="schema-cololight">schemas/schema-cololight.json</file>
<file alias="schema-hyperspi">schemas/schema-hyperspi.json</file>
<file alias="schema-home_assistant">schemas/schema-home_assistant.json</file>
</qresource>
</RCC>
Loading

0 comments on commit f1e847f

Please sign in to comment.