Skip to content

Commit dce1288

Browse files
committed
HTTPS support for homeassistant LED devices (#1886)
1 parent 2d016ae commit dce1288

File tree

8 files changed

+256
-120
lines changed

8 files changed

+256
-120
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
### ✨ Added
1414

15+
- HTTPS support for homeassistant LED devices (#1886)
16+
1517
---
1618

19+
1720
### 🔧 Changed
1821

1922
- **Fixes:**

assets/webconfig/i18n/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@
765765
"edt_dev_spec_useEntertainmentAPI_title": "Use Hue Entertainment API",
766766
"edt_dev_spec_useOrbSmoothing_title": "Use orb smoothing",
767767
"edt_dev_spec_useRgbwProtocol_title": "Use RGBW protocol",
768+
"edt_dev_spec_useSsl_title": "SSL",
768769
"edt_dev_spec_username_title": "Username",
769770
"edt_dev_spec_verbose_title": "Log all Hue commands",
770771
"edt_dev_spec_vid_title": "VID",
@@ -1239,3 +1240,4 @@
12391240
"ws_processing_exception": "Exception during Websocket message processing"
12401241
}
12411242

1243+

assets/webconfig/js/content_leds.js

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,23 +1412,25 @@ $(document).ready(function () {
14121412
break;
14131413

14141414
case "homeassistant":
1415-
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
1415+
const port = conf_editor.getEditor("root.specificOptions.port").getValue();
1416+
const useSsl = conf_editor.getEditor("root.specificOptions.useSsl").getValue();
1417+
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
14161418
if (token === "") {
14171419
return;
14181420
}
14191421

1420-
params = { host: host, token: token, filter: "states" };
1422+
params = { host, port, useSsl, token, filter: "states" };
14211423
getProperties_device(ledType, host, params);
14221424
break;
14231425

14241426
case "nanoleaf":
14251427
$('#btn_wiz_holder').show();
14261428

1427-
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
1429+
token = conf_editor.getEditor("root.specificOptions.token").getValue();
14281430
if (token === "") {
14291431
return;
14301432
}
1431-
params = { host: host, token: token };
1433+
params = { host, token };
14321434
getProperties_device(ledType, host, params);
14331435
break;
14341436

@@ -1586,22 +1588,24 @@ $(document).ready(function () {
15861588
if (token !== "") {
15871589
let params = {};
15881590

1589-
var host = "";
1591+
let host = "";
15901592
switch (ledType) {
15911593
case "homeassistant":
15921594
host = conf_editor.getEditor("root.specificOptions.host").getValue();
15931595
if (host === "") {
15941596
return
15951597
}
1596-
params = { host: host, token: token, filter: "states" };
1598+
const port = conf_editor.getEditor("root.specificOptions.port").getValue();
1599+
const useSsl = conf_editor.getEditor("root.specificOptions.useSsl").getValue();
1600+
params = { host, port, useSsl, token, filter: "states" };
15971601
break;
15981602

15991603
case "nanoleaf":
16001604
host = conf_editor.getEditor("root.specificOptions.host").getValue();
16011605
if (host === "") {
16021606
return
16031607
}
1604-
params = { host: host, token: token };
1608+
params = { host, token };
16051609
break;
16061610
default:
16071611
}
@@ -1610,6 +1614,54 @@ $(document).ready(function () {
16101614
}
16111615
});
16121616

1617+
conf_editor.watch('root.specificOptions.port', () => {
1618+
1619+
const port = conf_editor.getEditor("root.specificOptions.port").getValue();
1620+
1621+
if (port !== "") {
1622+
let params = {};
1623+
1624+
switch (ledType) {
1625+
case "homeassistant":
1626+
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
1627+
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
1628+
1629+
if (host === "" || token == "") {
1630+
return
1631+
}
1632+
const useSsl = conf_editor.getEditor("root.specificOptions.useSsl").getValue();
1633+
params = { host, port, useSsl, token, filter: "states" };
1634+
1635+
getProperties_device(ledType, host, params);
1636+
1637+
break;
1638+
}
1639+
}
1640+
});
1641+
1642+
conf_editor.watch('root.specificOptions.useSsl', () => {
1643+
1644+
const useSsl = conf_editor.getEditor("root.specificOptions.useSsl").getValue();
1645+
1646+
let params = {};
1647+
1648+
switch (ledType) {
1649+
case "homeassistant":
1650+
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
1651+
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
1652+
1653+
if (host === "" || token == "") {
1654+
return
1655+
}
1656+
const port = conf_editor.getEditor("root.specificOptions.port").getValue();
1657+
params = { host, port, useSsl, token, filter: "states" };
1658+
1659+
getProperties_device(ledType, host, params);
1660+
1661+
break;
1662+
}
1663+
});
1664+
16131665
//Yeelight
16141666
conf_editor.watch('root.specificOptions.lights', () => {
16151667
//Disable General Options, as LED count will be resolved from number of lights configured
@@ -1788,36 +1840,46 @@ $(document).ready(function () {
17881840

17891841
// Identify/ Test LED-Device
17901842
$("#btn_test_controller").off().on("click", function () {
1791-
var ledType = $("#leddevices").val();
1843+
const ledType = $("#leddevices").val();
17921844
let params = {};
17931845

17941846
switch (ledType) {
17951847
case "cololight":
17961848
case "wled":
1797-
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
1798-
params = { host: host };
1849+
{
1850+
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
1851+
params = { host: host };
1852+
}
17991853
break;
18001854

18011855
case "homeassistant":
1802-
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
1803-
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
1804-
const entityIds = conf_editor.getEditor("root.specificOptions.entityIds").getValue();
1805-
params = { host: host, token: token, entity_id: entityIds };
1856+
{
1857+
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
1858+
const port = conf_editor.getEditor("root.specificOptions.port").getValue();
1859+
const useSsl = conf_editor.getEditor("root.specificOptions.useSsl").getValue();
1860+
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
1861+
const entityIds = conf_editor.getEditor("root.specificOptions.entityIds").getValue();
1862+
params = { host, port, useSsl, token, entity_id: entityIds };
1863+
}
18061864
break;
18071865

18081866
case "nanoleaf":
1809-
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
1810-
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
1811-
params = { host: host, token: token };
1867+
{
1868+
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
1869+
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
1870+
params = { host, token };
1871+
}
18121872
break;
18131873

18141874
case "adalight":
18151875
case "skydimo":
1816-
var currentLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
1817-
params = Object.assign(conf_editor.getEditor("root.generalOptions").getValue(),
1818-
conf_editor.getEditor("root.specificOptions").getValue(),
1819-
{ currentLedCount }
1820-
);
1876+
{
1877+
const currentLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
1878+
params = Object.assign(conf_editor.getEditor("root.generalOptions").getValue(),
1879+
conf_editor.getEditor("root.specificOptions").getValue(),
1880+
{ currentLedCount }
1881+
);
1882+
}
18211883
default:
18221884
}
18231885

@@ -2815,3 +2877,4 @@ function nanoleafGeneratelayout(panelLayout, panelOrderTopDown, panelOrderLeftRi
28152877
return layoutObjects;
28162878
}
28172879

2880+

include/utils/NetUtils.h

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ inline bool resolveHostPort(const QString& address, QString& host, int& port)
106106
/// @param[out] hostAddress The resolved IP-Address
107107
/// @return True on success else false
108108
///
109-
inline bool resolveMdDnsHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
109+
inline bool resolveMDnsHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
110110
{
111111
bool isHostAddressOK{ false };
112112
if (!hostname.isEmpty())
@@ -176,7 +176,7 @@ inline bool resolveMdDnsHostToAddress(Logger* log, const QString& hostname, QHos
176176
/// @return A service record
177177
///
178178
#ifdef ENABLE_MDNS
179-
inline QMdnsEngine::Record resolveMdDnsServiceRecord(const QByteArray& serviceInstance)
179+
inline QMdnsEngine::Record resolveMDnsServiceRecord(const QByteArray& serviceInstance)
180180
{
181181
QMdnsEngine::Record serviceRecord;
182182

@@ -218,13 +218,13 @@ inline QMdnsEngine::Record resolveMdDnsServiceRecord(const QByteArray& serviceIn
218218
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress, int& port)
219219
{
220220
bool areHostAddressPartOK{ false };
221-
QString target {hostname};
221+
QString target{ hostname };
222222

223223
#ifdef ENABLE_MDNS
224224
if (hostname.endsWith("._tcp.local"))
225225
{
226226
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
227-
QMdnsEngine::Record const service = resolveMdDnsServiceRecord(hostname.toUtf8());
227+
QMdnsEngine::Record const service = resolveMDnsServiceRecord(hostname.toUtf8());
228228
if (!service.target().isEmpty())
229229
{
230230
if (!service.target().isEmpty())
@@ -244,24 +244,88 @@ inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddr
244244
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
245245
return false;
246246
}
247+
248+
QHostAddress resolvedAddress;
249+
if (NetUtils::resolveMDnsHostToAddress(log, target, resolvedAddress))
250+
{
251+
hostAddress = resolvedAddress;
252+
if (hostname != hostAddress.toString())
253+
{
254+
Info(log, "Resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
255+
}
256+
257+
if (NetUtils::isValidPort(log, port, hostAddress.toString()))
258+
{
259+
areHostAddressPartOK = true;
260+
}
261+
}
247262
}
263+
else
248264
#endif
265+
{
266+
return false;
267+
268+
}
269+
return areHostAddressPartOK;
270+
}
249271

250-
QHostAddress resolvedAddress;
251-
if (NetUtils::resolveMdDnsHostToAddress(log, target, resolvedAddress))
272+
///
273+
/// @brief Resolve a hostname(DNS) or mDNS service name into an IP-address. A given IP address will be passed through
274+
/// @param[in/out] log The logger of the caller to print
275+
/// @param[in/out] hostname The hostname/mDNS service name to be resolved, if mDNS the input hostname is replaced with the resolved mDNS hostname
276+
/// @param[in/out] port The port provided by the mDNS service, if not mDNS the input port is returned
277+
/// @return True on success else false
278+
///
279+
inline bool resolveMdnsHost(Logger* log, QString& hostname, int& port)
280+
{
281+
bool isResolved{ true };
282+
283+
#ifdef ENABLE_MDNS
284+
QString target{ hostname };
285+
286+
if (hostname.endsWith("._tcp.local"))
252287
{
253-
hostAddress = resolvedAddress;
254-
if (hostname != hostAddress.toString())
288+
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
289+
QMdnsEngine::Record const service = resolveMDnsServiceRecord(hostname.toUtf8());
290+
if (!service.target().isEmpty())
291+
{
292+
if (!service.target().isEmpty())
293+
{
294+
Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());
295+
target = service.target();
296+
port = service.port();
297+
}
298+
else
299+
{
300+
Error(log, "Failed to resolved service [%s] to an mDNS hostname", QSTRING_CSTR(hostname));
301+
return false;
302+
}
303+
}
304+
else
255305
{
256-
Info(log, "Resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
306+
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
307+
return false;
257308
}
258309

259-
if (NetUtils::isValidPort(log, port, hostAddress.toString()))
310+
QHostAddress resolvedAddress;
311+
if (NetUtils::resolveMDnsHostToAddress(log, target, resolvedAddress))
260312
{
261-
areHostAddressPartOK = true;
313+
QString const resolvedHostname = resolvedAddress.toString();
314+
if (hostname != resolvedHostname)
315+
{
316+
hostname = resolvedHostname;
317+
Info(log, "Resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostname));
318+
319+
}
320+
321+
if (!NetUtils::isValidPort(log, port, hostname))
322+
{
323+
isResolved = false;
324+
}
262325
}
263326
}
264-
return areHostAddressPartOK;
327+
#endif
328+
return isResolved;
265329
}
266330

267331
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)

0 commit comments

Comments
 (0)