2016-06-25 22:08:17 +02:00
# include <leddevice/LedDevice.h>
2016-10-09 22:22:17 +02:00
//QT include
2016-09-10 19:08:08 +02:00
# include <QResource>
# include <QStringList>
# include <QDir>
2017-04-09 22:28:32 +02:00
# include <QDateTime>
2020-02-10 15:21:58 +01:00
# include <QEventLoop>
# include <QTimer>
2020-06-28 23:05:32 +02:00
# include <QDateTime>
2017-04-09 22:28:32 +02:00
2017-03-21 17:55:46 +01:00
# include "hyperion/Hyperion.h"
2017-10-12 11:55:03 +02:00
# include <utils/JsonUtils.h>
2016-09-10 19:08:08 +02:00
2020-07-12 20:27:56 +02:00
//std includes
# include <sstream>
# include <iomanip>
LedDevice : : LedDevice ( const QJsonObject & deviceConfig , QObject * parent )
2019-01-01 19:47:07 +01:00
: QObject ( parent )
2020-07-12 20:27:56 +02:00
, _devConfig ( deviceConfig )
, _log ( Logger : : getInstance ( " LEDDEVICE " ) )
, _ledBuffer ( 0 )
, _refreshTimer ( nullptr )
, _refreshTimerInterval_ms ( 0 )
, _latchTime_ms ( 0 )
, _isRestoreOrigState ( false )
, _isEnabled ( false )
, _isDeviceInitialised ( false )
, _isDeviceReady ( false )
, _isDeviceInError ( false )
, _isInSwitchOff ( false )
, _lastWriteTime ( QDateTime : : currentDateTime ( ) )
, _isRefreshEnabled ( false )
2016-06-25 22:08:17 +02:00
{
2020-08-08 00:21:19 +02:00
_activeDeviceType = deviceConfig [ " type " ] . toString ( " UNSPECIFIED " ) . toLower ( ) ;
2016-06-25 22:08:17 +02:00
}
2016-07-13 11:18:12 +02:00
2019-01-01 19:47:07 +01:00
LedDevice : : ~ LedDevice ( )
{
2020-07-12 20:27:56 +02:00
delete _refreshTimer ;
2019-01-01 19:47:07 +01:00
}
2020-07-12 20:27:56 +02:00
void LedDevice : : start ( )
2016-07-13 11:18:12 +02:00
{
2020-07-12 20:27:56 +02:00
Info ( _log , " Start LedDevice '%s'. " , QSTRING_CSTR ( _activeDeviceType ) ) ;
// setup refreshTimer
if ( _refreshTimer = = nullptr )
{
_refreshTimer = new QTimer ( this ) ;
_refreshTimer - > setTimerType ( Qt : : PreciseTimer ) ;
_refreshTimer - > setInterval ( _refreshTimerInterval_ms ) ;
connect ( _refreshTimer , & QTimer : : timeout , this , & LedDevice : : rewriteLEDs ) ;
}
close ( ) ;
2020-02-14 21:58:10 +01:00
2020-07-12 20:27:56 +02:00
_isDeviceInitialised = false ;
2020-02-14 21:58:10 +01:00
// General initialisation and configuration of LedDevice
if ( init ( _devConfig ) )
{
2020-07-12 20:27:56 +02:00
// Everything is OK -> enable device
_isDeviceInitialised = true ;
setEnable ( true ) ;
2020-02-14 21:58:10 +01:00
}
2016-07-13 11:18:12 +02:00
}
2016-08-23 20:07:12 +02:00
2020-07-12 20:27:56 +02:00
void LedDevice : : stop ( )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
setEnable ( false ) ;
2020-02-10 15:21:58 +01:00
this - > stopRefreshTimer ( ) ;
2020-07-12 20:27:56 +02:00
}
2020-02-10 15:21:58 +01:00
2020-07-12 20:27:56 +02:00
int LedDevice : : open ( )
{
_isDeviceReady = true ;
int retval = 0 ;
return retval ;
}
int LedDevice : : close ( )
{
_isDeviceReady = false ;
int retval = 0 ;
return retval ;
2020-02-10 15:21:58 +01:00
}
2020-07-12 20:27:56 +02:00
void LedDevice : : setInError ( const QString & errorMsg )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
_isDeviceInError = true ;
_isDeviceReady = false ;
_isEnabled = false ;
2020-02-10 15:21:58 +01:00
this - > stopRefreshTimer ( ) ;
2020-07-12 20:27:56 +02:00
Error ( _log , " Device disabled, device '%s' signals error: '%s' " , QSTRING_CSTR ( _activeDeviceType ) , QSTRING_CSTR ( errorMsg ) ) ;
emit enableStateChanged ( _isEnabled ) ;
2020-02-10 15:21:58 +01:00
}
2017-03-21 17:55:46 +01:00
void LedDevice : : setEnable ( bool enable )
{
2020-07-12 20:27:56 +02:00
bool isSwitched = false ;
// switch off device when disabled, default: set black to LEDs when they should go off
if ( _isEnabled & & ! enable )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
isSwitched = switchOff ( ) ;
2019-07-13 11:23:56 +02:00
}
else
{
// switch on device when enabled
2020-07-12 20:27:56 +02:00
if ( ! _isEnabled & & enable )
2019-07-13 11:23:56 +02:00
{
2020-07-12 20:27:56 +02:00
isSwitched = switchOn ( ) ;
2019-07-13 11:23:56 +02:00
}
}
2020-07-12 20:27:56 +02:00
if ( isSwitched )
{
_isEnabled = enable ;
emit enableStateChanged ( enable ) ;
}
2017-03-21 17:55:46 +01:00
}
2020-02-10 15:21:58 +01:00
void LedDevice : : setActiveDeviceType ( const QString & deviceType )
2016-08-23 20:07:12 +02:00
{
2019-12-08 13:12:01 +01:00
_activeDeviceType = deviceType ;
2016-09-10 19:08:08 +02:00
}
2016-12-02 12:07:24 +01:00
bool LedDevice : : init ( const QJsonObject & deviceConfig )
{
2020-07-12 20:27:56 +02:00
Debug ( _log , " deviceConfig: [%s] " , QString ( QJsonDocument ( _devConfig ) . toJson ( QJsonDocument : : Compact ) ) . toUtf8 ( ) . constData ( ) ) ;
2020-02-14 21:58:10 +01:00
2018-12-27 23:11:32 +01:00
_colorOrder = deviceConfig [ " colorOrder " ] . toString ( " RGB " ) ;
2020-02-10 15:21:58 +01:00
setLedCount ( static_cast < unsigned int > ( deviceConfig [ " currentLedCount " ] . toInt ( 1 ) ) ) ; // property injected to reflect real led count
2020-07-12 20:27:56 +02:00
_latchTime_ms = deviceConfig [ " latchTime " ] . toInt ( _latchTime_ms ) ;
_refreshTimerInterval_ms = deviceConfig [ " rewriteTime " ] . toInt ( _refreshTimerInterval_ms ) ;
2018-12-27 23:11:32 +01:00
2020-07-12 20:27:56 +02:00
if ( _refreshTimerInterval_ms > 0 )
2017-04-09 22:28:32 +02:00
{
2020-07-12 20:27:56 +02:00
_isRefreshEnabled = true ;
2020-02-10 15:21:58 +01:00
2020-07-12 20:27:56 +02:00
if ( _refreshTimerInterval_ms < = _latchTime_ms )
2020-02-10 15:21:58 +01:00
{
int new_refresh_timer_interval = _latchTime_ms + 10 ;
2020-07-12 20:27:56 +02:00
Warning ( _log , " latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms " , _latchTime_ms , _refreshTimerInterval_ms , new_refresh_timer_interval ) ;
_refreshTimerInterval_ms = new_refresh_timer_interval ;
_refreshTimer - > setInterval ( _refreshTimerInterval_ms ) ;
2020-02-10 15:21:58 +01:00
}
2020-07-12 20:27:56 +02:00
Debug ( _log , " Refresh interval = %dms " , _refreshTimerInterval_ms ) ;
_refreshTimer - > setInterval ( _refreshTimerInterval_ms ) ;
2020-02-10 15:21:58 +01:00
2020-06-28 23:05:32 +02:00
_lastWriteTime = QDateTime : : currentDateTime ( ) ;
2017-04-09 22:28:32 +02:00
2020-02-10 15:21:58 +01:00
this - > startRefreshTimer ( ) ;
}
2016-12-02 12:07:24 +01:00
return true ;
}
2020-02-10 15:21:58 +01:00
void LedDevice : : startRefreshTimer ( )
2016-09-23 08:49:22 +02:00
{
2020-07-12 20:27:56 +02:00
if ( _isDeviceReady & & _isEnabled )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
_refreshTimer - > start ( ) ;
2020-02-10 15:21:58 +01:00
}
}
2017-03-21 17:55:46 +01:00
2020-02-10 15:21:58 +01:00
void LedDevice : : stopRefreshTimer ( )
{
2020-07-12 20:27:56 +02:00
_refreshTimer - > stop ( ) ;
2020-02-10 15:21:58 +01:00
}
2016-11-29 23:14:15 +01:00
2020-02-10 15:21:58 +01:00
int LedDevice : : updateLeds ( const std : : vector < ColorRgb > & ledValues )
{
int retval = 0 ;
2020-07-12 20:27:56 +02:00
if ( ! isEnabled ( ) | | ! _isDeviceReady | | _isDeviceInError )
2016-11-29 23:14:15 +01:00
{
2020-02-23 23:18:34 +01:00
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
2020-02-10 15:21:58 +01:00
return - 1 ;
2016-11-29 23:14:15 +01:00
}
2020-02-10 15:21:58 +01:00
else
2017-04-09 22:28:32 +02:00
{
2020-06-28 23:05:32 +02:00
qint64 elapsedTimeMs = _lastWriteTime . msecsTo ( QDateTime : : currentDateTime ( ) ) ;
if ( _latchTime_ms = = 0 | | elapsedTimeMs > = _latchTime_ms )
2020-02-10 15:21:58 +01:00
{
2020-06-28 23:05:32 +02:00
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
2020-02-10 15:21:58 +01:00
retval = write ( ledValues ) ;
2020-06-28 23:05:32 +02:00
_lastWriteTime = QDateTime : : currentDateTime ( ) ;
2020-02-10 15:21:58 +01:00
// if device requires refreshing, save Led-Values and restart the timer
2020-07-12 20:27:56 +02:00
if ( _isRefreshEnabled & & _isEnabled )
2020-02-10 15:21:58 +01:00
{
this - > startRefreshTimer ( ) ;
2020-07-12 20:27:56 +02:00
_lastLedValues = ledValues ;
2020-02-10 15:21:58 +01:00
}
}
else
{
2020-06-28 23:05:32 +02:00
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
2020-07-12 20:27:56 +02:00
if ( _isRefreshEnabled )
2020-02-10 15:21:58 +01:00
{
//Stop timer to allow for next non-refresh update
this - > stopRefreshTimer ( ) ;
}
}
2017-09-16 00:18:17 +02:00
}
2017-04-09 22:28:32 +02:00
return retval ;
2016-09-23 08:49:22 +02:00
}
2020-07-12 20:27:56 +02:00
int LedDevice : : rewriteLEDs ( )
2016-09-23 08:49:22 +02:00
{
2020-07-12 20:27:56 +02:00
int retval = - 1 ;
if ( _isDeviceReady & & _isEnabled )
{
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
// //:TESTING: Inject "white" output records to differentiate from normal writes
// _lastLedValues.clear();
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
// printLedValues(_lastLedValues);
// //:TESTING:
retval = write ( _lastLedValues ) ;
_lastWriteTime = QDateTime : : currentDateTime ( ) ;
}
else
{
// If Device is not ready stop timer
this - > stopRefreshTimer ( ) ;
}
return retval ;
2016-09-23 08:49:22 +02:00
}
2020-07-12 20:27:56 +02:00
int LedDevice : : writeBlack ( int numberOfBlack )
2019-12-08 13:12:01 +01:00
{
2020-07-12 20:27:56 +02:00
int rc = - 1 ;
2020-02-10 15:21:58 +01:00
2020-07-12 20:27:56 +02:00
for ( int i = 0 ; i < numberOfBlack ; i + + )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
if ( _latchTime_ms > 0 )
{
// Wait latch time before writing black
QEventLoop loop ;
2020-08-02 22:32:00 +02:00
QTimer : : singleShot ( _latchTime_ms , & loop , & QEventLoop : : quit ) ;
2020-07-12 20:27:56 +02:00
loop . exec ( ) ;
}
rc = write ( std : : vector < ColorRgb > ( static_cast < unsigned long > ( _ledCount ) , ColorRgb : : BLACK ) ) ;
2020-02-10 15:21:58 +01:00
}
2019-12-08 13:12:01 +01:00
return rc ;
}
2020-07-12 20:27:56 +02:00
bool LedDevice : : switchOn ( )
2017-09-16 00:18:17 +02:00
{
2020-07-12 20:27:56 +02:00
bool rc = false ;
if ( _isDeviceInitialised & & ! _isDeviceReady & & ! _isEnabled )
{
_isDeviceInError = false ;
if ( open ( ) < 0 )
{
rc = false ;
}
else
{
storeState ( ) ;
if ( powerOn ( ) )
{
_isEnabled = true ;
rc = true ;
}
}
}
return rc ;
2017-09-16 00:18:17 +02:00
}
2016-09-23 08:49:22 +02:00
2020-07-12 20:27:56 +02:00
bool LedDevice : : switchOff ( )
2016-10-08 08:14:36 +02:00
{
2020-07-12 20:27:56 +02:00
bool rc = false ;
if ( _isDeviceInitialised )
{
// Disable device to ensure no standard Led updates are written/processed
_isEnabled = false ;
_isInSwitchOff = true ;
this - > stopRefreshTimer ( ) ;
rc = true ;
if ( _isDeviceReady )
{
if ( _isRestoreOrigState )
{
//Restore devices state
restoreState ( ) ;
}
else
{
powerOff ( ) ;
}
}
if ( close ( ) < 0 )
{
rc = false ;
}
}
return rc ;
2016-10-08 08:14:36 +02:00
}
2016-11-29 23:14:15 +01:00
2020-07-12 20:27:56 +02:00
bool LedDevice : : powerOff ( )
2020-03-26 18:49:44 +01:00
{
2020-07-12 20:27:56 +02:00
bool rc = false ;
// Simulate power-off by writing a final "Black" to have a defined outcome
if ( writeBlack ( ) > = 0 )
{
rc = true ;
}
return rc ;
2020-03-26 18:49:44 +01:00
}
2020-07-12 20:27:56 +02:00
bool LedDevice : : powerOn ( )
2016-11-29 23:14:15 +01:00
{
2020-07-12 20:27:56 +02:00
bool rc = true ;
return rc ;
}
2020-02-10 15:21:58 +01:00
2020-07-12 20:27:56 +02:00
bool LedDevice : : storeState ( )
{
bool rc = true ;
if ( _isRestoreOrigState )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
// Save device's original state
// _originalStateValues = get device's state;
// store original power on/off state, if available
2020-02-10 15:21:58 +01:00
}
2020-07-12 20:27:56 +02:00
return rc ;
}
bool LedDevice : : restoreState ( )
{
bool rc = true ;
if ( _isRestoreOrigState )
2020-02-10 15:21:58 +01:00
{
2020-07-12 20:27:56 +02:00
// Restore device's original state
// update device using _originalStateValues
// update original power on/off state, if supported
2020-02-10 15:21:58 +01:00
}
2020-07-12 20:27:56 +02:00
return rc ;
}
QJsonObject LedDevice : : discover ( )
{
QJsonObject devicesDiscovered ;
devicesDiscovered . insert ( " ledDeviceType " , _activeDeviceType ) ;
QJsonArray deviceList ;
devicesDiscovered . insert ( " devices " , deviceList ) ;
Debug ( _log , " devicesDiscovered: [%s] " , QString ( QJsonDocument ( devicesDiscovered ) . toJson ( QJsonDocument : : Compact ) ) . toUtf8 ( ) . constData ( ) ) ;
return devicesDiscovered ;
}
QString LedDevice : : discoverFirst ( )
{
QString deviceDiscovered ;
Debug ( _log , " deviceDiscovered: [%s] " , QSTRING_CSTR ( deviceDiscovered ) ) ;
return deviceDiscovered ;
}
QJsonObject LedDevice : : getProperties ( const QJsonObject & params )
{
Debug ( _log , " params: [%s] " , QString ( QJsonDocument ( params ) . toJson ( QJsonDocument : : Compact ) ) . toUtf8 ( ) . constData ( ) ) ;
QJsonObject properties ;
QJsonObject deviceProperties ;
properties . insert ( " properties " , deviceProperties ) ;
Debug ( _log , " properties: [%s] " , QString ( QJsonDocument ( properties ) . toJson ( QJsonDocument : : Compact ) ) . toUtf8 ( ) . constData ( ) ) ;
return properties ;
}
void LedDevice : : setLedCount ( unsigned int ledCount )
{
_ledCount = ledCount ;
_ledRGBCount = _ledCount * sizeof ( ColorRgb ) ;
_ledRGBWCount = _ledCount * sizeof ( ColorRgbw ) ;
}
void LedDevice : : setLatchTime ( int latchTime_ms )
{
_latchTime_ms = latchTime_ms ;
Debug ( _log , " LatchTime updated to %dms " , this - > getLatchTime ( ) ) ;
2016-11-29 23:14:15 +01:00
}
2019-12-08 13:12:01 +01:00
add Hue EntertainmentAPI + Forwarder & other Fixes (#592)
* whitespaces + typo fixes
* JS / LGTM fixes
* SSDP Handler crash fix
* MessageForwarder handlePriorityChanges Slave fixes
* use aboutToQuit Signal
* complete rewriten Hue Entertainment API structure
combined Philips Hue and Entertainment API
with new MbedTLS based SSL UDP Provider
* add required cross-compile submodules
* logical rebuild fn: initLeds, setLights + new logs
-more detailed checks and error handling inside iniLeds and setLights
- logical script procedure before ProviderUdpSSL init
- first steps for multiple ProviderUdpSSL usage
- better fallback support to old RestAPI, if entertainment api is not supported
- just 4 u LordGrey: new log fn for cosmetic config outputs ;)
* add OSX CompileHowTo - undo from CrossCompileHowTo
* whitespace fixes
* lightID toString fix
* fix unsigned int E-API + debug output
* bugfixes, reworked black signal detection, wizard:
- change device config field light-ids from int to string -> real unsigned int fix
- add signal detection brightness minimum threshold value
0.0 for 0% brightness - 1.0 for 100% brightness to count for blacklight signal detection
reason: input may not 100% black, like mine - i have a deep dark gray input signal
-> my threshold value is set to 0.005 for 0.5% minimum brightness = 1 (from max 255) to count as black
- wizard optimations, with fallback without entertainment support (beta state)
- whitespace fixes
* cleanup + minor fixes
* change fixed Hue UPD SSL config to _devConfig paras
* Hotfix SSL Connection, new light models, wizard:
- Fix UPD SSL Connection failed Problems
- add new supported gamut C light models: LCG002, LCA001, LCA002, LCA003
- wizard: extend fallback support to classic mode + hints
* whitespace, typo fix
* uncheck useEntertainmentAPI, if noAPISupport detected + hint
* coredump fix -> add _blackLightsTimer nullptr init
* code cleanup / remove old debugs + whitespacefixes
* add gamut C LCP001, LCP002
* SSL UDP config made more flexible + remove qDebug
-> switch to hyerion.ng _log
-> replace logCommand with verbose
-> code cleanups etc...
* extended mbedtls debugging infos
* add adjustable ssl timeout settings
* error handling
* streamdebugger bugfixes
* UPDSSL psk / psk_identity bugfixes! + hue wizard fn typo fix +
- verbose option available without dependencies
- whitespace fixes
* Philips Hue Assistant now recognizes non-original bridges better...
+ Added note if no clientkey is set when using the entertainment API
+ User creation (+ clientkey) for non-original bridges can now also be used
+ Minor changes and bug fixes
* CMAKE mbedTLS detection
* minor bug fixes + code cleanups
* FindMbedTLS.cmake remove Path-Hints + wizard.js: ajax timeout handling
Test - content_grabber.js: run relevant code only, if V4L2_AVAIL is true:
conf_grabber don't displays other devices, if V4L2 is not available
* compile mbedtls via cmake as static lib
* remove libmbedtls-dev from compileHowto / scripts
* Fix Windows build
* Fix windows build (part 2)
* removed unnecessary osx x11 include directory path
* QTimer Shutdown bugfix
* cmake win32 fix + minor bugfixes
* cmake debug msg used mbedtls libs
* Bugfix: noSignalDetection wasn't switchedOn again
if no signal was previously detected
* Some code fixes based on alerts from lgtm.com
Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
2020-05-22 19:40:50 +02:00
void LedDevice : : printLedValues ( const std : : vector < ColorRgb > & ledValues )
2020-02-10 15:21:58 +01:00
{
std : : cout < < " LedValues [ " < < ledValues . size ( ) < < " ] [ " ;
for ( const ColorRgb & color : ledValues )
{
std : : cout < < color ;
}
std : : cout < < " ] " < < std : : endl ;
}
2020-07-12 20:27:56 +02:00
QString LedDevice : : uint8_t_to_hex_string ( const uint8_t * data , const qint64 size , qint64 number ) const
{
if ( number < = 0 | | number > size )
{
number = size ;
}
QByteArray bytes ( reinterpret_cast < const char * > ( data ) , number ) ;
# if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
return bytes . toHex ( ' : ' ) ;
# else
return bytes . toHex ( ) ;
# endif
}