Skip to content

Commit

Permalink
Handle Brightness & Black (hyperion-project#1818)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lord-Grey authored Dec 28, 2024
1 parent fd0d6b7 commit bc3ea9d
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 109 deletions.
168 changes: 83 additions & 85 deletions libsrc/leddevice/dev_net/LedDeviceHomeAssistant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,39 @@

// Constants
namespace {
const bool verbose = false;

// Configuration settings
const char CONFIG_HOST[] = "host";
const char CONFIG_PORT[] = "port";
const char CONFIG_AUTH_TOKEN[] = "token";
const char CONFIG_ENITYIDS[] = "entityIds";
const char CONFIG_BRIGHTNESS[] = "brightness";
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
const char CONFIG_FULL_BRIGHTNESS_AT_START[] = "fullBrightnessAtStart";
const char CONFIG_ON_OFF_BLACK[] = "switchOffOnBlack";
const char CONFIG_TRANSITIONTIME[] = "transitionTime";

const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
const bool DEFAULT_IS_FULL_BRIGHTNESS_AT_START = true;
const int BRI_MAX = 255;
const bool DEFAULT_IS_SWITCH_OFF_ON_BLACK = false;

// Home Assistant API
const int API_DEFAULT_PORT = 8123;
const char API_BASE_PATH[] = "/api/";
const char API_STATES[] = "states";
const char API_LIGHT_TURN_ON[] = "services/light/turn_on";
const char API_LIGHT_TURN_OFF[] = "services/light/turn_off";

const char ENTITY_ID[] = "entity_id";
const char RGB_COLOR[] = "rgb_color";
const char BRIGHTNESS[] = "brightness";
const char TRANSITION[] = "transition";
const char FLASH[] = "flash";

// // Home Assistant ssdp services
const char SSDP_ID[] = "ssdp:all";
const char SSDP_FILTER_HEADER[] = "ST";
const char SSDP_FILTER[] = "(.*)home-assistant.io(.*)";
const bool verbose = false;

// Configuration settings
const char CONFIG_HOST[] = "host";
const char CONFIG_PORT[] = "port";
const char CONFIG_AUTH_TOKEN[] = "token";
const char CONFIG_ENITYIDS[] = "entityIds";
const char CONFIG_BRIGHTNESS[] = "brightness";
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
const char CONFIG_FULL_BRIGHTNESS_AT_START[] = "fullBrightnessAtStart";
const char CONFIG_TRANSITIONTIME[] = "transitionTime";

const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
const bool DEFAULT_IS_FULL_BRIGHTNESS_AT_START = true;
const int BRI_MAX = 255;

// Home Assistant API
const int API_DEFAULT_PORT = 8123;
const char API_BASE_PATH[] = "/api/";
const char API_STATES[] = "states";
const char API_LIGHT_TURN_ON[] = "services/light/turn_on";
const char API_LIGHT_TURN_OFF[] = "services/light/turn_off";

const char ENTITY_ID[] = "entity_id";
const char RGB_COLOR[] = "rgb_color";
const char BRIGHTNESS[] = "brightness";
const char TRANSITION[] = "transition";
const char FLASH[] = "flash";

// // Home Assistant ssdp services
const char SSDP_ID[] = "ssdp:all";
const char SSDP_FILTER_HEADER[] = "ST";
const char SSDP_FILTER[] = "(.*)home-assistant.io(.*)";

} //End of constants

Expand All @@ -58,11 +56,12 @@ LedDeviceHomeAssistant::LedDeviceHomeAssistant(const QJsonObject& deviceConfig)
, _apiPort(API_DEFAULT_PORT)
, _isBrightnessOverwrite(DEFAULT_IS_BRIGHTNESS_OVERWRITE)
, _isFullBrightnessAtStart(DEFAULT_IS_FULL_BRIGHTNESS_AT_START)
, _brightness (BRI_MAX)
, _brightness(BRI_MAX)
, _transitionTime(0)
{
#ifdef ENABLE_MDNS
QMetaObject::invokeMethod(MdnsBrowser::getInstance().data(), "browseForServiceType",
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
#endif
}

Expand All @@ -81,7 +80,7 @@ bool LedDeviceHomeAssistant::init(const QJsonObject& deviceConfig)
{
bool isInitOK{ false };

if ( LedDevice::init(deviceConfig) )
if (LedDevice::init(deviceConfig))
{
// Overwrite non supported/required features
if (deviceConfig["rewriteTime"].toInt(0) > 0)
Expand All @@ -99,30 +98,28 @@ bool LedDeviceHomeAssistant::init(const QJsonObject& deviceConfig)
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
_isFullBrightnessAtStart = _devConfig[CONFIG_FULL_BRIGHTNESS_AT_START].toBool(DEFAULT_IS_FULL_BRIGHTNESS_AT_START);
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
_switchOffOnBlack = _devConfig[CONFIG_ON_OFF_BLACK].toBool(DEFAULT_IS_SWITCH_OFF_ON_BLACK);
int transitionTimeMs = _devConfig[CONFIG_TRANSITIONTIME].toInt(0);
_transitionTime = transitionTimeMs / 1000.0;

Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName));
Debug(_log, "Port : %d", _apiPort );
Debug(_log, "Port : %d", _apiPort);

Debug(_log, "Overwrite Brightn.: %s", _isBrightnessOverwrite ? "Yes" : "No" );
Debug(_log, "Overwrite Brightn.: %s", _isBrightnessOverwrite ? "Yes" : "No");
Debug(_log, "Set Brightness to : %d", _brightness);
Debug(_log, "Full Bri. at start: %s", _isFullBrightnessAtStart ? "Yes" : "No" );
Debug(_log, "Off on Black : %s", _switchOffOnBlack ? "Yes" : "No" );
Debug(_log, "Transition Time : %d ms", transitionTimeMs );
Debug(_log, "Full Bri. at start: %s", _isFullBrightnessAtStart ? "Yes" : "No");
Debug(_log, "Transition Time : %d ms", transitionTimeMs);

_lightEntityIds = _devConfig[ CONFIG_ENITYIDS ].toVariant().toStringList();
_lightEntityIds = _devConfig[CONFIG_ENITYIDS].toVariant().toStringList();
int configuredLightsCount = _lightEntityIds.size();

if ( configuredLightsCount == 0 )
if (configuredLightsCount == 0)
{
this->setInError( "No light entity-ids configured" );
this->setInError("No light entity-ids configured");
isInitOK = false;
}
else
{
Debug(_log, "Lights configured : %d", configuredLightsCount );
Debug(_log, "Lights configured : %d", configuredLightsCount);
isInitOK = true;
}
}
Expand All @@ -138,11 +135,11 @@ bool LedDeviceHomeAssistant::initLedsConfiguration()
QString lightEntityId = _lightEntityIds[0];

//Get properties for configured light entitiy to check availability
_restApi->setPath({ API_STATES, lightEntityId});
_restApi->setPath({ API_STATES, lightEntityId });
httpResponse response = _restApi->get();
if (response.error())
{
QString errorReason = QString("%1 get properties failed with error: '%2'").arg(_activeDeviceType,response.getErrorReason());
QString errorReason = QString("%1 get properties failed with error: '%2'").arg(_activeDeviceType, response.getErrorReason());
this->setInError(errorReason);
}
else
Expand Down Expand Up @@ -239,10 +236,10 @@ QJsonObject LedDeviceHomeAssistant::discover(const QJsonObject& /*params*/)
#ifdef ENABLE_MDNS
QString discoveryMethod("mDNS");
deviceList = MdnsBrowser::getInstance().data()->getServicesDiscoveredJson(
MdnsServiceRegister::getServiceType(_activeDeviceType),
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
DEFAULT_DISCOVER_TIMEOUT
);
MdnsServiceRegister::getServiceType(_activeDeviceType),
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
DEFAULT_DISCOVER_TIMEOUT
);
#else
QString discoveryMethod("ssdp");
deviceList = discoverSsdp();
Expand Down Expand Up @@ -288,7 +285,7 @@ QJsonObject LedDeviceHomeAssistant::getProperties(const QJsonObject& params)
QVector<QJsonValue> filteredVector;

// Iterate over the array and filter objects with entity_id starting with "light."
for (const QJsonValue &value : jsonArray)
for (const QJsonValue& value : jsonArray)
{
QJsonObject obj = value.toObject();
QString entityId = obj[ENTITY_ID].toString();
Expand All @@ -300,14 +297,14 @@ QJsonObject LedDeviceHomeAssistant::getProperties(const QJsonObject& params)
}

// Sort the filtered vector by "friendly_name" in ascending order
std::sort(filteredVector.begin(), filteredVector.end(), [](const QJsonValue &a, const QJsonValue &b) {
std::sort(filteredVector.begin(), filteredVector.end(), [](const QJsonValue& a, const QJsonValue& b) {
QString nameA = a.toObject()["attributes"].toObject()["friendly_name"].toString();
QString nameB = b.toObject()["attributes"].toObject()["friendly_name"].toString();
return nameA < nameB; // Ascending order
});
});
// Convert the sorted vector back to a QJsonArray
QJsonArray sortedArray;
for (const QJsonValue &value : filteredVector) {
for (const QJsonValue& value : filteredVector) {
sortedArray.append(value);
}

Expand Down Expand Up @@ -341,10 +338,10 @@ void LedDeviceHomeAssistant::identify(const QJsonObject& params)
{
if (openRestAPI())
{
QJsonArray lightEntityIds = params[ ENTITY_ID ].toArray();
QJsonArray lightEntityIds = params[ENTITY_ID].toArray();

_restApi->setPath(API_LIGHT_TURN_ON);
QJsonObject serviceAttributes{{ENTITY_ID, lightEntityIds}};
QJsonObject serviceAttributes{ {ENTITY_ID, lightEntityIds} };
serviceAttributes.insert(FLASH, "short");

httpResponse response = _restApi->post(serviceAttributes);
Expand All @@ -362,7 +359,7 @@ bool LedDeviceHomeAssistant::powerOn()
if (_isDeviceReady)
{
_restApi->setPath(API_LIGHT_TURN_ON);
QJsonObject serviceAttributes {{ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)}};
QJsonObject serviceAttributes{ {ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)} };

if (_isFullBrightnessAtStart)
{
Expand All @@ -389,7 +386,7 @@ bool LedDeviceHomeAssistant::powerOff()
if (_isDeviceReady)
{
_restApi->setPath(API_LIGHT_TURN_OFF);
QJsonObject serviceAttributes {{ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)}};
QJsonObject serviceAttributes{ {ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)} };
httpResponse response = _restApi->post(serviceAttributes);
if (response.error())
{
Expand All @@ -405,40 +402,41 @@ int LedDeviceHomeAssistant::write(const std::vector<ColorRgb>& ledValues)
{
int retVal = 0;

QJsonObject serviceAttributes {{ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)}};
QJsonObject serviceAttributes{ {ENTITY_ID, QJsonArray::fromStringList(_lightEntityIds)} };
ColorRgb ledValue = ledValues.at(0);

if (_switchOffOnBlack && ledValue == ColorRgb::BLACK)
// http://hostname:port/api/services/light/turn_on
// {
// "entity_id": [ entity-IDs ],
// "rgb_color": [R,G,B]
// }

_restApi->setPath(API_LIGHT_TURN_ON);
serviceAttributes.insert(RGB_COLOR, QJsonArray{ ledValue.red, ledValue.green, ledValue.blue });

int brightness = _brightness;

// Some devices cannot deal with a black color and brightness > 0
if (ledValue == ColorRgb::BLACK)
{
_restApi->setPath(API_LIGHT_TURN_OFF);
brightness = 0;
}
else
{
// http://hostname:port/api/services/light/turn_on
// {
// "entity_id": [ entity-IDs ],
// "rgb_color": [R,G,B]
// }

_restApi->setPath(API_LIGHT_TURN_ON);
QJsonArray rgbColor {ledValue.red, ledValue.green, ledValue.blue};
serviceAttributes.insert(RGB_COLOR, rgbColor);
// Add brightness attribute if applicable
if (brightness == 0 || _isBrightnessOverwrite)
{
serviceAttributes.insert(BRIGHTNESS, brightness);
}

if (_isBrightnessOverwrite)
{
serviceAttributes.insert(BRIGHTNESS, _brightness);
}
if (_transitionTime > 0)
{
// Transition time in seconds
serviceAttributes.insert(TRANSITION, _transitionTime);
}
if (_transitionTime > 0)
{
serviceAttributes.insert(TRANSITION, _transitionTime);
}

httpResponse response = _restApi->post(serviceAttributes);
if (response.error())
{
Warning(_log,"Updating lights failed with error: '%s'", QSTRING_CSTR(response.getErrorReason()) );
Warning(_log, "Updating lights failed with error: '%s'", QSTRING_CSTR(response.getErrorReason()));
retVal = -1;
}

Expand Down
1 change: 0 additions & 1 deletion libsrc/leddevice/dev_net/LedDeviceHomeAssistant.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ class LedDeviceHomeAssistant : LedDevice
bool _isBrightnessOverwrite;
bool _isFullBrightnessAtStart;
int _brightness;
bool _switchOffOnBlack;
/// Transition time in seconds
double _transitionTime;

Expand Down
26 changes: 3 additions & 23 deletions libsrc/leddevice/schemas/schema-homeassistant.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,6 @@
},
"propertyOrder": 4
},
"restoreOriginalState": {
"type": "boolean",
"format": "checkbox",
"title": "edt_dev_spec_restoreOriginalState_title",
"default": true,
"required": true,
"options": {
"hidden": true,
"infoText": "edt_dev_spec_restoreOriginalState_title_info"
},
"propertyOrder": 5
},
"overwriteBrightness": {
"type": "boolean",
"format": "checkbox",
Expand Down Expand Up @@ -84,14 +72,6 @@
"access": "advanced",
"propertyOrder": 7
},
"switchOffOnBlack": {
"type": "boolean",
"format": "checkbox",
"title": "edt_dev_spec_switchOffOnBlack_title",
"default": false,
"access": "advanced",
"propertyOrder": 8
},
"transitionTime": {
"type": "integer",
"title": "edt_dev_spec_transistionTime_title",
Expand All @@ -101,7 +81,7 @@
"maximum": 2000,
"required": false,
"access": "advanced",
"propertyOrder": 9
"propertyOrder": 8
},
"entityIds": {
"title": "edt_dev_spec_lightid_title",
Expand All @@ -115,7 +95,7 @@
"type": "string",
"title": "edt_dev_spec_lights_itemtitle"
},
"propertyOrder": 10
"propertyOrder": 9
},
"latchTime": {
"type": "integer",
Expand All @@ -128,7 +108,7 @@
"options": {
"infoText": "edt_dev_spec_latchtime_title_info"
},
"propertyOrder": 11
"propertyOrder": 10
}
},
"additionalProperties": true
Expand Down

0 comments on commit bc3ea9d

Please sign in to comment.