-1)
- hideEl(["device","pixelDecimation"]);
- else if (grabbers.indexOf('x11') > -1)
- hideEl(["device","width","height"]);
- else if (grabbers.indexOf('osx') > -1 )
- hideEl(["device","pixelDecimation"]);
- else if (grabbers.indexOf('amlogic') > -1)
- hideEl(["pixelDecimation"]);
- });
+ if (grabbers.indexOf('dispmanx') > -1)
+ hideEl(["device","pixelDecimation"]);
+ else if (grabbers.indexOf('x11') > -1)
+ hideEl(["device","width","height"]);
+ else if (grabbers.indexOf('osx') > -1 )
+ hideEl(["device","pixelDecimation"]);
+ else if (grabbers.indexOf('amlogic') > -1)
+ hideEl(["pixelDecimation"]);
+ });
- removeOverlay();
+ removeOverlay();
});
diff --git a/assets/webconfig/js/content_index.js b/assets/webconfig/js/content_index.js
index 6c986298..4d6fdcbf 100644
--- a/assets/webconfig/js/content_index.js
+++ b/assets/webconfig/js/content_index.js
@@ -163,7 +163,6 @@ $(document).ready(function () {
requestTokenAuthorization(loginToken)
else
loadContentTo("#page-content", "login")
-
}
});
diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js
index 8c411708..3f9db645 100755
--- a/assets/webconfig/js/content_leds.js
+++ b/assets/webconfig/js/content_leds.js
@@ -39,12 +39,12 @@ function createLedPreview(leds, origin){
{
var led = leds[idx];
var led_id='ledc_'+[idx];
- var bgcolor = "background-color:hsl("+(idx*360/leds.length)+",100%,50%);";
+ var bgcolor = "background-color:hsla("+(idx*360/leds.length)+",100%,50%,0.75);";
var pos = "left:"+(led.hmin * canvas_width)+"px;"+
"top:"+(led.vmin * canvas_height)+"px;"+
"width:"+((led.hmax-led.hmin) * (canvas_width-1))+"px;"+
"height:"+((led.vmax-led.vmin) * (canvas_height-1))+"px;";
- leds_html += ''+idx+'
';
+ leds_html += ''+((led.name) ? led.name : idx)+'
';
}
$('#leds_preview').html(leds_html);
$('#ledc_0').css({"background-color":"black","z-index":"12"});
@@ -496,9 +496,13 @@ $(document).ready(function() {
$("#leddevices").off().on("change", function() {
var generalOptions = window.serverSchema.properties.device;
- // Modified schema enty "hardwareLedCount" in generalOptions to minimum LedCount
+ // Modified schema entry "hardwareLedCount" in generalOptions to minimum LedCount
+ var ledType = $(this).val();
- var specificOptions = window.serverSchema.properties.alldevices[$(this).val()];
+ //philipshueentertainment backward fix
+ if(ledType == "philipshueentertainment") ledType = "philipshue";
+
+ var specificOptions = window.serverSchema.properties.alldevices[ledType];
conf_editor = createJsonEditor('editor_container', {
generalOptions : generalOptions,
specificOptions : specificOptions,
@@ -506,21 +510,19 @@ $(document).ready(function() {
var values_general = {};
var values_specific = {};
- var isCurrentDevice = (window.serverConfig.device.type == $(this).val());
+ var isCurrentDevice = (window.serverConfig.device.type == ledType);
- for(var key in window.serverConfig.device){
- if (key != "type" && key in generalOptions.properties)
- values_general[key] = window.serverConfig.device[key];
+ for(var key in window.serverConfig.device) {
+ if (key != "type" && key in generalOptions.properties) values_general[key] = window.serverConfig.device[key];
};
conf_editor.getEditor("root.generalOptions").setValue( values_general );
if (isCurrentDevice)
{
- var specificOptions_val = conf_editor.getEditor("root.specificOptions").getValue()
+ var specificOptions_val = conf_editor.getEditor("root.specificOptions").getValue();
for(var key in specificOptions_val){
- values_specific[key] = (key in window.serverConfig.device) ? window.serverConfig.device[key] : specificOptions_val[key];
+ values_specific[key] = (key in window.serverConfig.device) ? window.serverConfig.device[key] : specificOptions_val[key];
};
-
conf_editor.getEditor("root.specificOptions").setValue( values_specific );
};
@@ -528,18 +530,29 @@ $(document).ready(function() {
conf_editor.validate().length ? $('#btn_submit_controller').attr('disabled', true) : $('#btn_submit_controller').attr('disabled', false);
// led controller sepecific wizards
- if($(this).val() == "philipshue")
- {
- createHint("wizard", $.i18n('wiz_hue_title'), "btn_wiz_holder","btn_led_device_wiz");
- $('#btn_led_device_wiz').off().on('click',startWizardPhilipsHue);
- }
- else
- {
- $('#btn_wiz_holder').html("")
- $('#btn_led_device_wiz').off();
- }
+ $('#btn_wiz_holder').html("")
+ $('#btn_led_device_wiz').off();
+
+ if(ledType == "philipshue") {
+ $('#root_specificOptions_useEntertainmentAPI').bind("change", function() {
+ var ledWizardType = (this.checked) ? "philipshueentertainment" : ledType;
+ var data = { type: ledWizardType };
+ var hue_title = (this.checked) ? 'wiz_hue_e_title' : 'wiz_hue_title';
+ changeWizard(data, hue_title, startWizardPhilipsHue);
+ });
+ $("#root_specificOptions_useEntertainmentAPI").trigger("change");
+ }
+
+ function changeWizard(data, hint, fn) {
+ $('#btn_wiz_holder').html("")
+ createHint("wizard", $.i18n(hint), "btn_wiz_holder","btn_led_device_wiz");
+ $('#btn_led_device_wiz').off().on('click', data , fn);
+ }
});
+ //philipshueentertainment backward fix
+ if(window.serverConfig.device.type == "philipshueentertainment") window.serverConfig.device.type = "philipshue";
+
// create led device selection
var ledDevices = window.serverInfo.ledDevices.available;
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'ws2812spi'];
diff --git a/assets/webconfig/js/ledsim.js b/assets/webconfig/js/ledsim.js
index 75913b58..7fbdcbae 100644
--- a/assets/webconfig/js/ledsim.js
+++ b/assets/webconfig/js/ledsim.js
@@ -147,15 +147,19 @@ $(document).ready(function() {
//roundRect(ledsCanvasNodeCtx, led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height, 4, true, colors[idx])
//ledsCanvasNodeCtx.fillRect(led.hmin * canvas_width, led.vmin * canvas_height, (led.hmax-led.hmin) * canvas_width, (led.vmax-led.vmin) * canvas_height);
- ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba("+colors[cPos]+","+colors[cPos+1]+","+colors[cPos+2]+",0.9)" : "hsl("+(idx*360/leds.length)+",100%,50%)";
+ ledsCanvasNodeCtx.fillStyle = (useColor) ? "rgba("+colors[cPos]+","+colors[cPos+1]+","+colors[cPos+2]+",0.75)" : "hsla("+(idx*360/leds.length)+",100%,50%,0.75)";
ledsCanvasNodeCtx.fill(twoDPaths[idx]);
ledsCanvasNodeCtx.stroke(twoDPaths[idx]);
if(toggleLedsNum)
{
- ledsCanvasNodeCtx.fillStyle = "blue";
+ //ledsCanvasNodeCtx.shadowOffsetX = 1;
+ //ledsCanvasNodeCtx.shadowOffsetY = 1;
+ //ledsCanvasNodeCtx.shadowColor = "black";
+ //ledsCanvasNodeCtx.shadowBlur = 4;
+ ledsCanvasNodeCtx.fillStyle = "white";
ledsCanvasNodeCtx.textAlign = "center";
- ledsCanvasNodeCtx.fillText(idx, (led.hmin * canvas_width) + ( ((led.hmax-led.hmin) * canvas_width) / 2), (led.vmin * canvas_height) + ( ((led.vmax-led.vmin) * canvas_height) / 2));
+ ledsCanvasNodeCtx.fillText(((led.name) ? led.name : idx), (led.hmin * canvas_width) + ( ((led.hmax-led.hmin) * canvas_width) / 2), (led.vmin * canvas_height) + ( ((led.vmax-led.vmin) * canvas_height) / 2));
}
// increment colorsPosition
diff --git a/assets/webconfig/js/lib/jquery.i18n.js b/assets/webconfig/js/lib/jquery.i18n.js
index 5fbfffb2..32d9b10d 100644
--- a/assets/webconfig/js/lib/jquery.i18n.js
+++ b/assets/webconfig/js/lib/jquery.i18n.js
@@ -247,7 +247,7 @@
String.locale = String.locale || $( 'html' ).attr( 'lang' );
if ( !String.locale ) {
- if ( typeof window.navigator !== undefined ) {
+ if ( typeof window.navigator !== 'undefined' ) {
nav = window.navigator;
String.locale = nav.language || nav.userLanguage || '';
} else {
diff --git a/assets/webconfig/js/lib/jquery.i18n.language.js b/assets/webconfig/js/lib/jquery.i18n.language.js
index e596fbc8..be413924 100644
--- a/assets/webconfig/js/lib/jquery.i18n.language.js
+++ b/assets/webconfig/js/lib/jquery.i18n.language.js
@@ -360,7 +360,7 @@
// Check if the restore to Latin number flag is set:
if ( integer ) {
- if ( parseFloat( num, 10 ) === num ) {
+ if ( parseFloat( num ) === num ) {
return num;
}
@@ -381,7 +381,7 @@
}
}
- return integer ? parseFloat( convertedNumber, 10 ) : convertedNumber;
+ return integer ? parseFloat( convertedNumber ) : convertedNumber;
},
/**
diff --git a/assets/webconfig/js/settings.js b/assets/webconfig/js/settings.js
index 37e407b6..774603d8 100644
--- a/assets/webconfig/js/settings.js
+++ b/assets/webconfig/js/settings.js
@@ -157,20 +157,16 @@ $(document).ready( function() {
{
if(lsys != window.wSess[i].host+':'+window.wSess[i].port)
{
- var hyperionAddress
-
- if (window.wSess[i].address.indexOf(':') > -1 && window.wSess[i].address.length == 36)
- hyperionAddress = 'http://['+window.wSess[i].address+']:'+window.wSess[i].port
- else
- hyperionAddress = 'http://'+window.wSess[i].address+':'+window.wSess[i].port
-
- $('#id_select').append(createSelOpt(hyperionAddress, window.wSess[i].host))
+ var hyperionAddress = window.wSess[i].address;
+ if(hyperionAddress.indexOf(':') > -1 && hyperionAddress.length == 36) hyperionAddress = '['+hyperionAddress+']';
+ hyperionAddress = 'http://'+hyperionAddress+':'+window.wSess[i].port;
+ $('#id_select').append(createSelOpt(hyperionAddress, window.wSess[i].name));
}
}
$('#id_btn_saveset').off().on('click',function() {
$("#loading_overlay").addClass("overlay");
- window.location.href = $('#id_select').val()
+ window.location.href = $('#id_select').val();
});
});
diff --git a/assets/webconfig/js/streamer.js b/assets/webconfig/js/streamer.js
index a7861a68..ee457f66 100644
--- a/assets/webconfig/js/streamer.js
+++ b/assets/webconfig/js/streamer.js
@@ -2,7 +2,7 @@ $(document).ready( function() {
// check if browser supports streaming
if(window.navigator.mediaDevices && window.navigator.mediaDevices.getDisplayMedia){
- $("#btn_streamer").toggle()
+ $("#btn_streamer").toggle();
}
// variables
diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js
index 60b4e283..845dcb7f 100644
--- a/assets/webconfig/js/ui_utils.js
+++ b/assets/webconfig/js/ui_utils.js
@@ -109,7 +109,7 @@ function loadContent(event, forceRefresh)
var lastSelectedInstance = getStorage('lastSelectedInstance', false);
if (lastSelectedInstance && (lastSelectedInstance != window.currentHyperionInstance))
- if (typeof(window.serverInfo.instance[lastSelectedInstance].running) !== 'undefined' && window.serverInfo.instance[lastSelectedInstance].running)
+ if (typeof(window.serverInfo.instance[lastSelectedInstance].running) !== 'undefined' && window.serverInfo.instance[lastSelectedInstance].running)
instanceSwitch(lastSelectedInstance);
else
removeStorage('lastSelectedInstance', false);
@@ -890,12 +890,12 @@ function getReleases(callback)
continue;
if(releases[i].tag_name.includes('alpha'))
- {
+ {
if (sem = semverLite.gt(releases[i].tag_name, highestAlphaRelease.tag_name))
- highestAlphaRelease = releases[i];
+ highestAlphaRelease = releases[i];
}
else if (releases[i].tag_name.includes('beta'))
- {
+ {
if (sem = semverLite.gt(releases[i].tag_name, highestBetaRelease.tag_name))
highestBetaRelease = releases[i];
}
@@ -907,7 +907,7 @@ function getReleases(callback)
else
{
if (semverLite.gt(releases[i].tag_name, highestRelease.tag_name))
- highestRelease = releases[i];
+ highestRelease = releases[i];
}
}
window.latestStableVersion = highestRelease;
@@ -915,7 +915,7 @@ function getReleases(callback)
window.latestAlphaVersion= highestAlphaRelease;
window.latestRcVersion = highestRcRelease;
-
+
if(window.serverConfig.general.watchedVersionBranch == "Beta" && semverLite.gt(highestBetaRelease.tag_name, highestRelease.tag_name))
window.latestVersion = highestBetaRelease;
else
@@ -951,4 +951,4 @@ function handleDarkMode()
setStorage("darkMode", "on", false);
$('#btn_darkmode_icon').removeClass('fa fa-moon-o');
$('#btn_darkmode_icon').addClass('fa fa-sun-o');
-}
\ No newline at end of file
+}
diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js
index de33979e..b019b581 100644
--- a/assets/webconfig/js/wizard.js
+++ b/assets/webconfig/js/wizard.js
@@ -1,31 +1,31 @@
//clear priority and other tasks if people reload the page or lost connection while a wizard was active
$(window.hyperion).one("ready", function(event) {
- if(getStorage("wizardactive") === 'true')
- {
- requestPriorityClear();
- setStorage("wizardactive", false);
- if(getStorage("kodiAddress") != null)
- {
- kodiAddress = getStorage("kodiAddress");
- sendToKodi("stop");
- }
- }
+ if(getStorage("wizardactive") === 'true')
+ {
+ requestPriorityClear();
+ setStorage("wizardactive", false);
+ if(getStorage("kodiAddress") != null)
+ {
+ kodiAddress = getStorage("kodiAddress");
+ sendToKodi("stop");
+ }
+ }
});
-function resetWizard()
+function resetWizard(reload)
{
- $("#wizard_modal").modal('hide');
- clearInterval(wIntveralId);
- requestPriorityClear();
- setStorage("wizardactive", false);
- $('#wizp1').toggle(true);
- $('#wizp2').toggle(false);
- $('#wizp3').toggle(false);
- //cc
- if(withKodi)
- sendToKodi("stop");
- step = 0;
- location.reload();
+ $("#wizard_modal").modal('hide');
+ clearInterval(wIntveralId);
+ requestPriorityClear();
+ setStorage("wizardactive", false);
+ $('#wizp1').toggle(true);
+ $('#wizp2').toggle(false);
+ $('#wizp3').toggle(false);
+ //cc
+ if(withKodi)
+ sendToKodi("stop");
+ step = 0;
+ if(!reload) location.reload();
}
//rgb byte order wizard
@@ -34,128 +34,128 @@ var new_rgb_order;
function changeColor()
{
- var color = $("#wiz_canv_color").css('background-color');
+ var color = $("#wiz_canv_color").css('background-color');
- if (color == 'rgb(255, 0, 0)')
- {
- $("#wiz_canv_color").css('background-color','rgb(0, 255, 0)');
- requestSetColor('0','255','0');
- }
- else
- {
- $("#wiz_canv_color").css('background-color','rgb(255, 0, 0)');
- requestSetColor('255','0','0');
- }
+ if (color == 'rgb(255, 0, 0)')
+ {
+ $("#wiz_canv_color").css('background-color','rgb(0, 255, 0)');
+ requestSetColor('0','255','0');
+ }
+ else
+ {
+ $("#wiz_canv_color").css('background-color','rgb(255, 0, 0)');
+ requestSetColor('255','0','0');
+ }
}
function startWizardRGB()
{
- //create html
- $('#wiz_header').html(''+$.i18n('wiz_rgb_title'));
- $('#wizp1_body').html(''+$.i18n('wiz_rgb_title')+'
'+$.i18n('wiz_rgb_intro1')+'
'+$.i18n('wiz_rgb_intro2')+'
');
- $('#wizp1_footer').html('');
- $('#wizp2_body').html(''+$.i18n('wiz_rgb_expl')+'
');
- $('#wizp2_body').append('');
- $('#wizp2_body').append('');
- $('#wizp2_body').append(' | |
| |
');
- $('#wizp2_footer').html('');
+ //create html
+ $('#wiz_header').html(''+$.i18n('wiz_rgb_title'));
+ $('#wizp1_body').html(''+$.i18n('wiz_rgb_title')+'
'+$.i18n('wiz_rgb_intro1')+'
'+$.i18n('wiz_rgb_intro2')+'
');
+ $('#wizp1_footer').html('');
+ $('#wizp2_body').html(''+$.i18n('wiz_rgb_expl')+'
');
+ $('#wizp2_body').append('');
+ $('#wizp2_body').append('');
+ $('#wizp2_body').append(' | |
| |
');
+ $('#wizp2_footer').html('');
- //open modal
- $("#wizard_modal").modal({
- backdrop : "static",
- keyboard: false,
- show: true
- });
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop : "static",
+ keyboard: false,
+ show: true
+ });
- //listen for continue
- $('#btn_wiz_cont').off().on('click',function() {
- beginWizardRGB();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click',function() {
+ beginWizardRGB();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
}
function beginWizardRGB()
{
- $("#wiz_switchtime_select").off().on('change',function() {
- clearInterval(wIntveralId);
- var time = $("#wiz_switchtime_select").val();
- wIntveralId = setInterval(function() { changeColor(); }, time*1000);
- });
+ $("#wiz_switchtime_select").off().on('change',function() {
+ clearInterval(wIntveralId);
+ var time = $("#wiz_switchtime_select").val();
+ wIntveralId = setInterval(function() { changeColor(); }, time*1000);
+ });
- $('.wselect').change(function () {
- var rgb_order = window.serverConfig.device.colorOrder.split("");
- var redS = $("#wiz_r_select").val();
- var greenS = $("#wiz_g_select").val();
- var blueS = rgb_order.toString().replace(/,/g,"").replace(redS, "").replace(greenS,"");
+ $('.wselect').change(function () {
+ var rgb_order = window.serverConfig.device.colorOrder.split("");
+ var redS = $("#wiz_r_select").val();
+ var greenS = $("#wiz_g_select").val();
+ var blueS = rgb_order.toString().replace(/,/g,"").replace(redS, "").replace(greenS,"");
- for (var i = 0; i'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_white_title'));
- sendToKodi('playP',"white");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_white_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 3)
- {
- updateWEditor(["gammaRed","gammaGreen","gammaBlue"]);
- h = ''+$.i18n('wiz_cc_adjustgamma')+'
';
- if(withKodi)
- {
- sendToKodi('playP',"HGradient");
- h +='';
- }
- else
- h += ''+$.i18n('wiz_cc_lettvshowm', "gey_1, grey_2, grey_3, HGradient, VGradient")+'
';
- $('#wiz_cc_desc').html(h);
- $('#wiz_cc_btn_sp').off().on('click', function(){
- switchPicture(["VGradient","grey_1","grey_2","grey_3","HGradient"]);
- });
- }
- if(step == 4)
- {
- updateWEditor(["red"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_red_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_red_title'));
- sendToKodi('playP',"red");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_red_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 5)
- {
- updateWEditor(["green"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_green_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_green_title'));
- sendToKodi('playP',"green");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_green_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 6)
- {
- updateWEditor(["blue"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_blue_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_blue_title'));
- sendToKodi('playP',"blue");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_blue_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 7)
- {
- updateWEditor(["cyan"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_cyan_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_cyan_title'));
- sendToKodi('playP',"cyan");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_cyan_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 8)
- {
- updateWEditor(["magenta"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_magenta_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_magenta_title'));
- sendToKodi('playP',"magenta");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_magenta_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 9)
- {
- updateWEditor(["yellow"]);
- h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_yellow_title'));
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_yellow_title'));
- sendToKodi('playP',"yellow");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_yellow_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 10)
- {
- updateWEditor(["backlightThreshold","backlightColored"]);
- h = $.i18n('wiz_cc_backlight');
- if(withKodi)
- {
- h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_black_title'));
- sendToKodi('playP',"black");
- }
- else
- h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_black_title'));
- $('#wiz_cc_desc').html(h);
- }
- if(step == 11)
- {
- updateWEditor([""], true);
- h = ''+$.i18n('wiz_cc_testintro')+'
';
- if(withKodi)
- {
- h += ''+$.i18n('wiz_cc_testintrok')+'
';
- sendToKodi('stop');
- for(var i = 0; i';
- }
- h +='';
- }
- else
- h += ''+$.i18n('wiz_cc_testintrowok')+' '+$.i18n('wiz_cc_link')+'
';
- h += ''+$.i18n('wiz_cc_summary')+'
';
- $('#wiz_cc_desc').html(h);
+ if(step == 2)
+ {
+ updateWEditor(["white"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_white_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_white_title'));
+ sendToKodi('playP',"white");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_white_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 3)
+ {
+ updateWEditor(["gammaRed","gammaGreen","gammaBlue"]);
+ h = ''+$.i18n('wiz_cc_adjustgamma')+'
';
+ if(withKodi)
+ {
+ sendToKodi('playP',"HGradient");
+ h +='';
+ }
+ else
+ h += ''+$.i18n('wiz_cc_lettvshowm', "gey_1, grey_2, grey_3, HGradient, VGradient")+'
';
+ $('#wiz_cc_desc').html(h);
+ $('#wiz_cc_btn_sp').off().on('click', function(){
+ switchPicture(["VGradient","grey_1","grey_2","grey_3","HGradient"]);
+ });
+ }
+ if(step == 4)
+ {
+ updateWEditor(["red"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_red_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_red_title'));
+ sendToKodi('playP',"red");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_red_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 5)
+ {
+ updateWEditor(["green"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_green_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_green_title'));
+ sendToKodi('playP',"green");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_green_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 6)
+ {
+ updateWEditor(["blue"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_blue_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_blue_title'));
+ sendToKodi('playP',"blue");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_blue_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 7)
+ {
+ updateWEditor(["cyan"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_cyan_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_cyan_title'));
+ sendToKodi('playP',"cyan");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_cyan_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 8)
+ {
+ updateWEditor(["magenta"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_magenta_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_magenta_title'));
+ sendToKodi('playP',"magenta");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_magenta_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 9)
+ {
+ updateWEditor(["yellow"]);
+ h = $.i18n('wiz_cc_adjustit',$.i18n('edt_conf_color_yellow_title'));
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_yellow_title'));
+ sendToKodi('playP',"yellow");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_yellow_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 10)
+ {
+ updateWEditor(["backlightThreshold","backlightColored"]);
+ h = $.i18n('wiz_cc_backlight');
+ if(withKodi)
+ {
+ h += '
'+$.i18n('wiz_cc_kodishould',$.i18n('edt_conf_color_black_title'));
+ sendToKodi('playP',"black");
+ }
+ else
+ h += '
'+$.i18n('wiz_cc_lettvshow',$.i18n('edt_conf_color_black_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if(step == 11)
+ {
+ updateWEditor([""], true);
+ h = ''+$.i18n('wiz_cc_testintro')+'
';
+ if(withKodi)
+ {
+ h += ''+$.i18n('wiz_cc_testintrok')+'
';
+ sendToKodi('stop');
+ for(var i = 0; i';
+ }
+ h +='';
+ }
+ else
+ h += ''+$.i18n('wiz_cc_testintrowok')+' '+$.i18n('wiz_cc_link')+'
';
+ h += ''+$.i18n('wiz_cc_summary')+'
';
+ $('#wiz_cc_desc').html(h);
- $('.videobtn').off().on('click', function(e){
- if(e.target.id == "stop")
- sendToKodi("stop");
- else
- sendToKodi("playV",e.target.id+'.mp4');
+ $('.videobtn').off().on('click', function(e){
+ if(e.target.id == "stop")
+ sendToKodi("stop");
+ else
+ sendToKodi("playV",e.target.id+'.mp4');
- $(this).attr("disabled", true);
- setTimeout(function(){$('.videobtn').attr("disabled", false)},10000);
- });
+ $(this).attr("disabled", true);
+ setTimeout(function(){$('.videobtn').attr("disabled", false)},10000);
+ });
- $('#btn_wiz_next').attr("disabled", true);
- $('#btn_wiz_save').toggle(true);
- }
- else
- {
- $('#btn_wiz_next').attr("disabled", false);
- $('#btn_wiz_save').toggle(false);
- }
+ $('#btn_wiz_next').attr("disabled", true);
+ $('#btn_wiz_save').toggle(true);
+ }
+ else
+ {
+ $('#btn_wiz_next').attr("disabled", false);
+ $('#btn_wiz_save').toggle(false);
+ }
}
function updateWEditor(el, all)
{
- for (var key in cobj)
- {
- if(all === true || el[0] == key || el[1] == key || el[2] == key)
- $('#editor_container_wiz [data-schemapath*=".'+profile+'.'+key+'"]').toggle(true);
- else
- $('#editor_container_wiz [data-schemapath*=".'+profile+'.'+key+'"]').toggle(false);
- }
+ for (var key in cobj)
+ {
+ if(all === true || el[0] == key || el[1] == key || el[2] == key)
+ $('#editor_container_wiz [data-schemapath*=".'+profile+'.'+key+'"]').toggle(true);
+ else
+ $('#editor_container_wiz [data-schemapath*=".'+profile+'.'+key+'"]').toggle(false);
+ }
}
function startWizardCC()
{
- //create html
- $('#wiz_header').html(''+$.i18n('wiz_cc_title'));
- $('#wizp1_body').html(''+$.i18n('wiz_cc_title')+'
'+$.i18n('wiz_cc_intro1')+'
');
- $('#wizp1_footer').html('');
- $('#wizp2_body').html('');
- $('#wizp2_footer').html('');
+ //create html
+ $('#wiz_header').html(''+$.i18n('wiz_cc_title'));
+ $('#wizp1_body').html(''+$.i18n('wiz_cc_title')+'
'+$.i18n('wiz_cc_intro1')+'
');
+ $('#wizp1_footer').html('');
+ $('#wizp2_body').html('');
+ $('#wizp2_footer').html('');
- //open modal
- $("#wizard_modal").modal({
- backdrop : "static",
- keyboard: false,
- show: true
- });
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop : "static",
+ keyboard: false,
+ show: true
+ });
- $('#wiz_cc_kodiip').off().on('change',function() {
- kodiAddress = $(this).val();
- setStorage("kodiAddress", kodiAddress);
- sendToKodi("msg", $.i18n('wiz_cc_kodimsg_start'), function(cb){
- if(cb == "error")
- {
- $('#kodi_status').html(''+$.i18n('wiz_cc_kodidiscon')+'
'+$.i18n('wiz_cc_kodidisconlink')+' '+$.i18n('wiz_cc_link')+'
');
- withKodi = false;
- }
- else
- {
- $('#kodi_status').html(''+$.i18n('wiz_cc_kodicon')+'
');
- withKodi = true;
- }
+ $('#wiz_cc_kodiip').off().on('change',function() {
+ kodiAddress = $(this).val();
+ setStorage("kodiAddress", kodiAddress);
+ sendToKodi("msg", $.i18n('wiz_cc_kodimsg_start'), function(cb){
+ if(cb == "error")
+ {
+ $('#kodi_status').html(''+$.i18n('wiz_cc_kodidiscon')+'
'+$.i18n('wiz_cc_kodidisconlink')+' '+$.i18n('wiz_cc_link')+'
');
+ withKodi = false;
+ }
+ else
+ {
+ $('#kodi_status').html(''+$.i18n('wiz_cc_kodicon')+'
');
+ withKodi = true;
+ }
- $('#btn_wiz_cont').attr('disabled', false);
- });
- });
+ $('#btn_wiz_cont').attr('disabled', false);
+ });
+ });
- //listen for continue
- $('#btn_wiz_cont').off().on('click',function() {
- beginWizardCC();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click',function() {
+ beginWizardCC();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
- $('#wiz_cc_kodiip').trigger("change");
- colorLength = window.serverConfig.color.channelAdjustment;
- cobj = window.schema.color.properties.channelAdjustment.items.properties;
- websAddress = document.location.hostname+':'+window.serverConfig.webConfig.port;
- imgAddress = 'http://'+websAddress+'/img/cc/';
- setStorage("wizardactive", true);
+ $('#wiz_cc_kodiip').trigger("change");
+ colorLength = window.serverConfig.color.channelAdjustment;
+ cobj = window.schema.color.properties.channelAdjustment.items.properties;
+ websAddress = document.location.hostname+':'+window.serverConfig.webConfig.port;
+ imgAddress = 'http://'+websAddress+'/img/cc/';
+ setStorage("wizardactive", true);
- //check profile count
- if(colorLength.length > 1)
- {
- $('#multi_cali').html(''+$.i18n('wiz_cc_morethanone')+'
');
- for(var i = 0; i 1)
+ {
+ $('#multi_cali').html(''+$.i18n('wiz_cc_morethanone')+'
');
+ for(var i = 0; i'+$.i18n('wiz_hue_title'));
- $('#wizp1_body').html(''+$.i18n('wiz_hue_title')+'
'+$.i18n('wiz_hue_intro1')+'
');
- $('#wizp1_footer').html('');
- $('#wizp2_body').html('');
- $('#wh_topcontainer').append(''+$.i18n('wiz_hue_desc1')+'
');
- $('#wh_topcontainer').append('');
- $('#wizp2_body').append(''+$.i18n('wiz_hue_desc2')+'
');
- createTable("lidsh", "lidsb", "hue_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'),$.i18n('wiz_hue_pos'),$.i18n('wiz_hue_ident')], true));
- $('#wizp2_footer').html('');
- $('#wizp3_body').html(''+$.i18n('wiz_hue_press_link')+'
');
+ if(typeof e.data.type != "undefined") hueType = e.data.type;
- //open modal
- $("#wizard_modal").modal({
- backdrop : "static",
- keyboard: false,
- show: true
- });
+ //create html
- //listen for continue
- $('#btn_wiz_cont').off().on('click',function() {
- beginWizardHue();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
+ var hue_title = 'wiz_hue_title';
+ var hue_intro1 = 'wiz_hue_intro1';
+ var hue_desc1 = 'wiz_hue_desc1';
+ var hue_create_user = 'wiz_hue_create_user';
+ if(hueType == 'philipshueentertainment')
+ {
+ hue_title = 'wiz_hue_e_title';
+ hue_intro1 = 'wiz_hue_e_intro1';
+ hue_desc1 = 'wiz_hue_e_desc1';
+ hue_create_user = 'wiz_hue_e_create_user';
+ }
+ $('#wiz_header').html(''+$.i18n(hue_title));
+ $('#wizp1_body').html(''+$.i18n(hue_title)+'
'+$.i18n(hue_intro1)+'
');
+ $('#wizp1_footer').html('');
+ $('#wizp2_body').html('');
+ $('#wh_topcontainer').append(''+$.i18n(hue_desc1)+'
');
+ $('#wh_topcontainer').append();
+ $('#wh_topcontainer').append('');
+ if(hueType == 'philipshue')
+ {
+ $('#usrcont').append('
');
+ }
+ if(hueType == 'philipshueentertainment')
+ {
+ $('#usrcont').append('
');
+ }
+ $('#usrcont').append('
');
+ if(hueType == 'philipshueentertainment')
+ {
+ $('#wizp2_body').append(''+$.i18n('wiz_hue_e_desc2')+'
');
+ createTable("gidsh", "gidsb", "hue_grp_ids_t");
+ $('.gidsh').append(createTableRow([$.i18n('edt_dev_spec_groupId_title'),$.i18n('wiz_hue_e_use_group')], true));
+ $('#wizp2_body').append(''+$.i18n('wiz_hue_e_desc3')+'
');
+ }
+ else
+ {
+ $('#wizp2_body').append(''+$.i18n('wiz_hue_desc2')+'
');
+ }
+ createTable("lidsh", "lidsb", "hue_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'),$.i18n('wiz_hue_pos'),$.i18n('wiz_hue_ident')], true));
+ $('#wizp2_footer').html('');
+ $('#wizp3_body').html(''+$.i18n('wiz_hue_press_link')+'
');
+
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop : "static",
+ keyboard: false,
+ show: true
+ });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click',function() {
+ beginWizardHue();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
}
-function checkHueBridge(cb,hueUser){
- var usr = "";
+function checkHueBridge(cb,hueUser) {
+ var usr = (typeof hueUser != "undefined") ? hueUser : 'config';
+ if(usr == 'config') $('#wiz_hue_discovered').html("");
+ $.ajax({
+ url: 'http://'+hueIPs[hueIPsinc].internalipaddress+'/api/'+usr,
+ type: "GET",
+ dataType: "json",
+ success: function( json ) {
+ if (json.config) {
+ cb(true, usr);
+ } else if( json.name && json.bridgeid && json.modelid) {
+ $('#wiz_hue_discovered').html("Bridge: " + json.name + ", Modelid: " + json.modelid + ", API-Version: " + json.apiversion);
+ cb(true);
+ } else {
+ cb(false);
+ }
- if(typeof hueUser != "undefined")
- usr = hueUser;
-
- $.ajax({
- url: 'http://'+hueIPs[hueIPsinc].internalipaddress+'/api/'+usr,
- contentType: 'application/json',
- type: 'GET',
- timeout: 2000
- })
- .done( function( data, textStatus, jqXHR ) {
- if( Array.isArray(data) && data[0].error)
- {
- if ( data[0].error.type == 3 || data[0].error.type == 4)
- {
- cb(true, usr);
- }
- else
- {
- cb(false);
- }
- }
- else
- {
- cb(true, usr);
- }
-
- })
- .fail( function( jqXHR, textStatus ) {
- cb(false);
- });
+ },
+ timeout: 2500
+ }).fail(function() {
+ cb(false);
+ });
}
-function checkUserResult(reply, usr){
+function checkBridgeResult(reply, usr){
+ if(reply)
+ {
+ //abort checking, first reachable result is used
+ $('#wiz_hue_ipstate').html("");
+ $('#ip').val(hueIPs[hueIPsinc].internalipaddress)
- if(reply)
- {
- $('#wiz_hue_usrstate').html("");
- $('#wiz_hue_create_user').toggle(false);
- $('#user').val(usr);
- get_hue_lights();
- }
- else
- {
- $('#wiz_hue_usrstate').html($.i18n('wiz_hue_failure_user'));
- $('#wiz_hue_create_user').toggle(true);
- }
+ //now check hue user on this bridge
+ $('#usrcont').toggle(true);
+ checkHueBridge(checkUserResult,$('#user').val() ? $('#user').val() : "newdeveloper");
+ }
+ else
+ {
+ //increment and check again
+ if(hueIPs.length-1 > hueIPsinc)
+ {
+ hueIPsinc++;
+ checkHueBridge(checkBridgeResult);
+ }
+ else
+ {
+ $('#usrcont').toggle(false);
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ }
+ }
};
-function checkBridgeResult(reply){
- if(reply)
- {
- //abort checking, first reachable result is used
- $('#wiz_hue_ipstate').html("");
- $('#ip').val(hueIPs[hueIPsinc].internalipaddress)
+function checkUserResult(reply, usr) {
- //now check hue user on this bridge
- $('#usrcont').toggle(true);
- checkHueBridge(checkUserResult,$('#user').val() ? $('#user').val() : "newdeveloper");
- }
- else
- {
- //increment and check again
- if(hueIPs.length-1 > hueIPsinc)
- {
- hueIPsinc++;
- checkHueBridge(checkBridgeResult);
- }
- else
- {
- $('#usrcont').toggle(false);
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- }
- }
+ if(reply)
+ {
+ $('#user').val(usr);
+ if(hueType == 'philipshueentertainment' && $('#clientkey').val() == "") {
+ $('#usrcont').toggle(true);
+ $('#wiz_hue_usrstate').html($.i18n('wiz_hue_e_clientkey_needed'));
+ $('#wiz_hue_create_user').toggle(true);
+ } else {
+ $('#wiz_hue_usrstate').html("");
+ $('#wiz_hue_create_user').toggle(false);
+ if(hueType == 'philipshue')
+ {
+ get_hue_lights();
+ }
+ if(hueType == 'philipshueentertainment')
+ {
+ get_hue_groups();
+ }
+ }
+ }
+ else
+ {
+ $('#wiz_hue_usrstate').html($.i18n('wiz_hue_failure_user'));
+ $('#wiz_hue_create_user').toggle(true);
+ }
};
- function assignHuePos(id, pos)
- {
- var i = null;
-
- if(pos == "top")
- i = huePosTop;
- else if(pos == "bottom")
- i = huePosBottom;
- else if(pos == "left")
- i = huePosLeft;
- else if(pos == "right")
- i = huePosRight;
- else
- i = huePosEntire;
-
- return i;
- }
-
-function identHueId(id, off)
+function assignHuePos(id, pos)
{
- if(off !== true)
- {
- setTimeout(identHueId,1500,id,true);
- var put_data = '{"on":true,"bri":254,"hue":47000,"sat":254}';
- }
- else
- {
- var put_data = '{"on":false}';
- }
+ var i = null;
- $.ajax({
- url: 'http://'+$('#ip').val()+'/api/'+$('#user').val()+'/lights/'+id+'/state',
- type: 'PUT',
- timeout: 2000,
-
- data: put_data
- })
+ if(pos == "top")
+ i = huePosTop;
+ else if(pos == "topleft")
+ i = huePosTopLeft;
+ else if(pos == "topright")
+ i = huePosTopRight;
+ else if(pos == "bottom")
+ i = huePosBottom;
+ else if(pos == "bottomleft")
+ i = huePosBottomLeft;
+ else if(pos == "bottomright")
+ i = huePosBottomRight;
+ else if(pos == "left")
+ i = huePosLeft;
+ else if(pos == "lefttop")
+ i = huePosLeftTop;
+ else if(pos == "leftmiddle")
+ i = huePosLeftMiddle;
+ else if(pos == "leftbottom")
+ i = huePosLeftBottom;
+ else if(pos == "right")
+ i = huePosRight;
+ else if(pos == "righttop")
+ i = huePosRightTop;
+ else if(pos == "rightmiddle")
+ i = huePosRightMiddle;
+ else if(pos == "rightbottom")
+ i = huePosRightBottom;
+ else
+ i = huePosEntire;
+
+ i.name = lightIDs[id].name;
+ return i;
+}
+
+function identHueId(id, off, oState)
+{
+ if(off !== true)
+ {
+ setTimeout(identHueId,1500,id,true,oState);
+ var put_data = '{"on":true,"bri":254,"hue":47000,"sat":254}';
+ }
+ else
+ {
+ var put_data = '{"on":'+oState.on+',"bri":' + oState.bri +',"hue":' + oState.hue +',"sat":' + oState.sat +'}';
+ }
+
+ $.ajax({
+ url: 'http://'+$('#ip').val()+'/api/'+$('#user').val()+'/lights/'+id+'/state',
+ type: 'PUT',
+ timeout: 2000,
+ data: put_data
+ })
+}
+
+function useGroupId(id)
+{
+ $('#groupId').val(id);
+ groupLights = groupIDs[id].lights;
+ groupLightsLocations = groupIDs[id].locations;
+ get_hue_lights();
}
function getHueIPs(){
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_searchb'));
- $.ajax({
- url: 'https://discovery.meethue.com',
- crossDomain: true,
- type: 'GET',
- timeout: 3000
- })
- .done( function( data, textStatus, jqXHR ) {
- if(data.length == 0)
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- else
- {
- hueIPs = data;
- checkHueBridge(checkBridgeResult);
- }
- })
- .fail( function( jqXHR, textStatus ) {
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- });
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_searchb'));
+ $.ajax({
+ url: 'https://discovery.meethue.com',
+ crossDomain: true,
+ type: 'GET',
+ timeout: 3000
+ })
+ .done( function( data, textStatus, jqXHR ) {
+ if(data.length == 0) {
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ } else {
+ hueIPs = data;
+ checkHueBridge(checkBridgeResult);
+ }
+ })
+ .fail( function( jqXHR, textStatus ) {
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ });
};
+//return editor Value
+function eV(vn)
+{
+ return (vn) ? conf_editor.getEditor("root.specificOptions." + vn).getValue() : "";
+}
+
function beginWizardHue()
{
- var usr = conf_editor.getEditor("root.specificOptions.username").getValue();
- if(usr != "")
- {
- $('#user').val(usr);
- }
+ var usr = eV("username");
+ if(usr != "") {
+ $('#user').val(usr);
+ }
- //check if ip is empty/reachable/search for bridge
- if(conf_editor.getEditor("root.specificOptions.output").getValue() == "")
- {
- getHueIPs();
- }
- else
- {
- var ip = conf_editor.getEditor("root.specificOptions.output").getValue();
- $('#ip').val(ip);
- hueIPs.push({internalipaddress : ip});
- checkHueBridge(checkBridgeResult);
- }
+ if(hueType == 'philipshueentertainment') {
+ var clkey = eV("clientkey");
+ if(clkey != "")
+ {
+ $('#clientkey').val(clkey);
+ }
+ }
+ //check if ip is empty/reachable/search for bridge
+ if(eV("output") == "")
+ {
+ getHueIPs();
+ }
+ else
+ {
+ var ip = eV("output");
+ $('#ip').val(ip);
+ hueIPs.unshift({internalipaddress : ip});
+ if(usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ }else{
+ checkHueBridge(checkBridgeResult);
+ }
+ }
- $('#retry_bridge').off().on('click', function(){
- hueIPs.push({internalipaddress : $('#ip').val()});
- hueIPsinc = 0;
- checkHueBridge(checkBridgeResult);
- });
+ $('#retry_bridge').off().on('click', function(){
+ if($('#ip').val()!="") hueIPs.unshift({internalipaddress : $('#ip').val()});
+ hueIPsinc = 0;
+ var usr = $('#user').val();
+ if(usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ }else{
+ checkHueBridge(checkBridgeResult);
+ }
+ });
- $('#retry_usr').off().on('click', function(){
- checkHueBridge(checkUserResult,$('#user').val() ? $('#user').val() : "newdeveloper");
- });
+ $('#retry_usr').off().on('click', function(){
+ checkHueBridge(checkUserResult,$('#user').val() ? $('#user').val() : "newdeveloper");
+ });
- $('#btn_wiz_save').off().on("click", function(){
- var hueLedConfig = [];
- var finalLightIds = [];
+ $('#wiz_hue_create_user').off().on('click',function() {
+ if($('#ip').val()!="") hueIPs.unshift({internalipaddress : $('#ip').val()});
+ createHueUser();
+ });
- //create hue led config
- for(var key in lightIDs)
- {
- if($('#hue_'+key).val() != "disabled")
- {
- hueLedConfig.push(assignHuePos(key, $('#hue_'+key).val()));
- finalLightIds.push(parseInt(key));
- }
- }
+ $('#btn_wiz_save').off().on("click", function(){
+ var hueLedConfig = [];
+ var finalLightIds = [];
- var ledCount= Object.keys(lightIDs).length;
+ //create hue led config
+ for(var key in lightIDs)
+ {
+ if(hueType == 'philipshueentertainment')
+ {
+ if(groupLights.indexOf(key) == -1) continue;
+ }
+ if($('#hue_'+key).val() != "disabled")
+ {
+ finalLightIds.push(key);
+ var idx_content = assignHuePos(key, $('#hue_'+key).val());
+ hueLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
+ }
+ }
- window.serverConfig.leds = hueLedConfig;
+ var sc = window.serverConfig;
+ sc.leds = hueLedConfig;
- //Adjust gamma, brightness and compensation
- var c = window.serverConfig.color.channelAdjustment[0];
- c.gammaBlue = 1.0;
- c.gammaRed = 1.0;
- c.gammaGreen = 1.0;
- c.brightness = 100;
- c.brightnessCompensation = 0;
+ //Adjust gamma, brightness and compensation
+ var c = sc.color.channelAdjustment[0];
+ c.gammaBlue = 1.0;
+ c.gammaRed = 1.0;
+ c.gammaGreen = 1.0;
+ c.brightness = 100;
+ c.brightnessCompensation = 0;
- //device config
- var d = window.serverConfig.device;
- d.output = $('#ip').val();
- d.lightIds = finalLightIds;
- d.username = $('#user').val();
- d.type = "philipshue";
- d.hardwareLedCount = ledCount;
- d.transitiontime = 1;
- d.switchOffOnBlack = true;
+ //device config
+ var d = sc.device;
+ d.output = $('#ip').val();
+ d.username = $('#user').val();
+ d.type = 'philipshue';
+ d.colorOrder = 'rgb';
+ d.lightIds = finalLightIds;
+ d.latchTime = 0;
+ d.transitiontime = parseInt(eV("transitiontime") );
+ d.restoreOriginalState = (eV("restoreOriginalState") == true);
+ d.switchOffOnBlack = (eV("switchOffOnBlack") == true);
+ d.brightnessFactor = parseFloat(eV("brightnessFactor"));
- //smoothing off
- window.serverConfig.smoothing.enable = false;
+ d.clientkey = $('#clientkey').val();
+ d.groupId = parseInt($('#groupId').val());
+ d.blackLightsTimeout = parseInt(eV("blackLightsTimeout"));
+ d.brightnessMin = parseFloat(eV("brightnessMin"));
+ d.brightnessMax = parseFloat(eV("brightnessMax"));
+ d.brightnessThreshold = parseFloat(eV("brightnessThreshold"));
+ d.sslReadTimeout = parseInt(eV("sslReadTimeout"));
+ d.sslHSTimeoutMin = parseInt(eV("sslHSTimeoutMin"));
+ d.sslHSTimeoutMax = parseInt(eV("sslHSTimeoutMax"));
+ d.verbose = (eV("verbose") == true);
+ d.debugStreamer = (eV("debugStreamer") == true);
+ d.debugLevel = (eV("debugLevel"));
- requestWriteConfig(window.serverConfig, true);
- resetWizard();
- });
+ if(hueType == 'philipshue')
+ {
+ d.useEntertainmentAPI = false;
+ d.hardwareLedCount = finalLightIds.length;
+ d.rewriteTime = 0;
+ d.verbose = false;
+ //smoothing off
+ sc.smoothing.enable = false;
+ }
- $('#btn_wiz_abort').off().on('click', resetWizard);
+ if(hueType == 'philipshueentertainment')
+ {
+ d.useEntertainmentAPI = true;
+ d.hardwareLedCount = groupLights.length;
+ d.rewriteTime = 20;
+ //smoothing on
+ sc.smoothing.enable = true;
+ }
+ requestWriteConfig(sc, true);
+ resetWizard();
+ });
+
+ $('#btn_wiz_abort').off().on('click', resetWizard);
}
function createHueUser()
{
- var connectionRetries = 30;
- var data = {"devicetype":"hyperion#"+Date.now()};
- var UserInterval = setInterval(function(){
- $.ajax({
- type: "POST",
- url: 'http://'+$("#ip").val()+'/api',
- processData: false,
- timeout: 1000,
- contentType: 'application/json',
- data: JSON.stringify(data),
- success: function(r) {
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(false);
- $('#wizp3').toggle(true);
+ var connectionRetries = 30;
+ var data = {"devicetype":"hyperion#"+Date.now()}
+ if(hueType == 'philipshueentertainment')
+ {
+ data = {"devicetype":"hyperion#"+Date.now(), "generateclientkey":true}
+ }
+ var UserInterval = setInterval(function(){
+ $.ajax({
+ type: "POST",
+ url: 'http://'+$("#ip").val()+'/api',
+ processData: false,
+ timeout: 1000,
+ contentType: 'application/json',
+ data: JSON.stringify(data),
+ success: function(r) {
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(false);
+ $('#wizp3').toggle(true);
- connectionRetries--;
- $("#connectionTime").html(connectionRetries);
- if(connectionRetries == 0)
- {
- abortConnection(UserInterval);
- }
- else
- {
- if (typeof r[0].error != 'undefined')
- {
- console.log(connectionRetries+": link not pressed");
- }
- if (typeof r[0].success != 'undefined')
- {
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
- $('#user').val(r[0].success.username);
- checkHueBridge(checkUserResult,r[0].success.username);
- clearInterval(UserInterval);
- }
- }
- },
- error: function(XMLHttpRequest, textStatus, errorThrown) {
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
- clearInterval(UserInterval);
- }
- });
- },1000);
+ connectionRetries--;
+ $("#connectionTime").html(connectionRetries);
+ if(connectionRetries == 0) {
+ abortConnection(UserInterval);
+ }
+ else
+ {
+ if (typeof r[0].error != 'undefined') {
+ console.log(connectionRetries+": link not pressed");
+ }
+ if (typeof r[0].success != 'undefined') {
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+ if(r[0].success.username != 'undefined') {
+ $('#user').val(r[0].success.username);
+ conf_editor.getEditor("root.specificOptions.username").setValue( r[0].success.username );
+ }
+ if(hueType == 'philipshueentertainment')
+ {
+ if(r[0].success.clientkey != 'undefined') {
+ $('#clientkey').val(r[0].success.clientkey);
+ conf_editor.getEditor("root.specificOptions.clientkey").setValue( r[0].success.clientkey );
+ }
+ }
+ checkHueBridge(checkUserResult,r[0].success.username);
+ clearInterval(UserInterval);
+ }
+ }
+ },
+ error: function(XMLHttpRequest, textStatus, errorThrown) {
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+ clearInterval(UserInterval);
+ }
+ });
+ },1000);
+}
+
+function get_hue_groups(){
+ $.ajax({
+ type: "GET",
+ url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/groups',
+ processData: false,
+ contentType: 'application/json',
+ success: function(r) {
+ if(Object.keys(r).length > 0)
+ {
+ $('#wh_topcontainer').toggle(false);
+ $('#hue_grp_ids_t').toggle(true);
+
+ groupIDs = r;
+
+ var gC = 0;
+ for(var groupid in r)
+ {
+ if(r[groupid].type=='Entertainment')
+ {
+ $('.gidsb').append(createTableRow([groupid+' ('+r[groupid].name+')', '']));
+ gC++;
+ }
+ }
+ if(gC == 0)
+ {
+ noAPISupport('wiz_hue_e_noegrpids');
+ }
+ }
+ else
+ {
+ noAPISupport('wiz_hue_e_nogrpids');
+ }
+ }
+ });
+}
+
+function noAPISupport(txt)
+{
+ showNotification('danger', $.i18n('wiz_hue_e_title'), $.i18n('wiz_hue_e_noapisupport_hint'));
+ conf_editor.getEditor("root.specificOptions.useEntertainmentAPI").setValue( false );
+ $("#root_specificOptions_useEntertainmentAPI").trigger("change");
+ $('#btn_wiz_holder').append(''+$.i18n('wiz_hue_e_noapisupport_hint')+'
');
+ $('#hue_grp_ids_t').toggle(false);
+ var txt = (txt) ? $.i18n(txt) : $.i18n('wiz_hue_e_nogrpids');
+ $(''+txt+'
'+$.i18n('wiz_hue_e_noapisupport')+'
').insertBefore('#wizp2_body #hue_ids_t');
+ $('#hue_id_headline').html($.i18n('wiz_hue_desc2'));
+ hueType = 'philipshue';
+ get_hue_lights();
+}
+
+function get_light_state(id){
+ $.ajax({
+ type: "GET",
+ url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/lights/'+id,
+ processData: false,
+ contentType: 'application/json',
+ success: function(r) {
+ if(Object.keys(r).length > 0)
+ {
+ identHueId(id, false, r['state']);
+ }
+ }
+ });
}
function get_hue_lights(){
- $.ajax({
- type: "GET",
- url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/lights',
- processData: false,
- contentType: 'application/json',
- success: function(r) {
- if(Object.keys(r).length > 0)
- {
- $('#wh_topcontainer').toggle(false);
- $('#hue_ids_t, #btn_wiz_save').toggle(true);
- lightIDs = r;
+ $.ajax({
+ type: "GET",
+ url: 'http://'+$("#ip").val()+'/api/'+$("#user").val()+'/lights',
+ processData: false,
+ contentType: 'application/json',
+ success: function(r) {
+ if(Object.keys(r).length > 0)
+ {
+ if(hueType == 'philipshue')
+ {
+ $('#wh_topcontainer').toggle(false);
+ }
+ $('#hue_ids_t, #btn_wiz_save').toggle(true);
+ lightIDs = r;
+ var lightOptions = [
+ "top", "topleft", "topright",
+ "bottom", "bottomleft", "bottomright",
+ "left", "lefttop", "leftmiddle", "leftbottom",
+ "right", "righttop", "rightmiddle", "rightbottom",
+ "entire"
+ ];
- for(var lightid in r)
- {
+ if(hueType == 'philipshue')
+ {
+ lightOptions.unshift("disabled");
+ }
- $('.lidsb').append(createTableRow([lightid+' ('+r[lightid].name+')', '','']));
- }
+ $('.lidsb').html("");
+ var pos = "";
+ for(var lightid in r)
+ {
+ if(hueType == 'philipshueentertainment')
+ {
+ if(groupLights.indexOf(lightid) == -1) continue;
- $('.hue_sel_watch').bind("change", function(){
- var cC = 0;
- for(var key in lightIDs)
- {
- if($('#hue_'+key).val() != "disabled")
- {
- cC++;
- }
- }
- cC == 0 ? $('#btn_wiz_save').attr("disabled",true) : $('#btn_wiz_save').attr("disabled",false);
- });
+ if(groupLightsLocations.hasOwnProperty(lightid))
+ {
+ lightLocation = groupLightsLocations[lightid];
+ var x = lightLocation[0];
+ var y = lightLocation[1];
+ var z = lightLocation[2];
+ var xval = (x < 0) ? "left" : "right";
+ if(z != 1 && x >= -0.25 && x <= 0.25 ) xval = "";
+ switch (z)
+ {
+ case 1: // top / Ceiling height
+ pos = "top" + xval;
+ break;
+ case 0: // middle / TV height
+ pos = (xval == "" && y >= 0.75) ? "bottom" : xval + "middle";
+ break;
+ case -1: // bottom / Ground height
+ pos = xval + "bottom";
+ break;
+ }
+ }
+ }
+ var options = "";
+ for(var opt in lightOptions)
+ {
+ var val = lightOptions[opt];
+ var txt = (val != 'entire' && val != 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_hue_ids_';
+ options+= '';
+ }
+ $('.lidsb').append(createTableRow([lightid+' ('+r[lightid].name+')', '','']));
+ }
- $('.hue_sel_watch').trigger('change');
- }
- else
- {
- $('#wizp2_body').html(''+$.i18n('wiz_hue_noids')+'
')
- }
- }
- });
+ if(hueType != 'philipshueentertainment')
+ {
+ $('.hue_sel_watch').bind("change", function(){
+ var cC = 0;
+ for(var key in lightIDs)
+ {
+ if($('#hue_'+key).val() != "disabled")
+ {
+ cC++;
+ }
+ }
+ cC == 0 ? $('#btn_wiz_save').attr("disabled",true) : $('#btn_wiz_save').attr("disabled",false);
+ });
+ }
+ $('.hue_sel_watch').trigger('change');
+ }
+ else
+ {
+ var txt = ''+$.i18n('wiz_hue_noids')+'
';
+ $('#wizp2_body').append(txt);
+ }
+ }
+ });
}
function abortConnection(UserInterval){
- clearInterval(UserInterval);
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
- $("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
+ clearInterval(UserInterval);
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+ $("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
}
diff --git a/bin/compile.sh b/bin/compile.sh
index a399b8a7..5a282bd1 100755
--- a/bin/compile.sh
+++ b/bin/compile.sh
@@ -5,7 +5,7 @@ CFG="${2:-Release}"
INST="$( [ "${3:-}" = "install" ] && echo true || echo false )"
sudo apt-get update
-sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev libturbojpeg0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libssl-dev || exit 1
+sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev libturbojpeg0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libssl-dev libjpeg-dev libqt5sql5-sqlite zlib1g-dev || exit 1
if [ -e /dev/vc-cma -a -e /dev/vc-mem ]
then
diff --git a/bin/remove_hyperion.sh b/bin/remove_hyperion.sh
index da3defe6..e07489cf 100644
--- a/bin/remove_hyperion.sh
+++ b/bin/remove_hyperion.sh
@@ -19,7 +19,7 @@ fi
#Welcome message
echo '*******************************************************************************'
-echo 'This script will remove Hyperion and it´s services'
+echo 'This script will remove Hyperion and its services'
echo '-----> Please BACKUP your hyperion.config.json if necessary <-----'
echo 'Created by brindosch - hyperion-project.org - the official Hyperion source.'
echo '*******************************************************************************'
@@ -29,7 +29,7 @@ if [ "$1" = "" ]; then
#Prompt for confirmation to proceed
while true
do
- echo -n "---> Do you really want to remove Hyperion and it´s services? (y or n) :"
+ echo -n "---> Do you really want to remove Hyperion and its services? (y or n) :"
read CONFIRM
case $CONFIRM in
y|Y|YES|yes|Yes) break ;;
diff --git a/cmake/Findmbedtls.cmake b/cmake/Findmbedtls.cmake
new file mode 100644
index 00000000..9fd21bc7
--- /dev/null
+++ b/cmake/Findmbedtls.cmake
@@ -0,0 +1,25 @@
+find_path(MBEDTLS_INCLUDE_DIR mbedtls/ssl.h)
+
+find_library(MBEDTLS_SSL_LIBRARY mbedtls)
+find_library(MBEDTLS_X509_LIBRARY mbedx509)
+find_library(MBEDTLS_CRYPTO_LIBRARY mbedcrypto)
+
+set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_X509_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY})
+
+if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+ file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _MBEDTLS_VERSION_STRING REGEX "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
+ string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*" "\\1" MBEDTLS_VERSION "${_MBEDTLS_VERSION_STRING}")
+endif ()
+
+if (MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES AND MBEDTLS_VERSION)
+ find_package_handle_standard_args(mbedtls
+ REQUIRED_VARS
+ MBEDTLS_INCLUDE_DIR
+ MBEDTLS_LIBRARIES
+ VERSION_VAR
+ MBEDTLS_VERSION
+ )
+
+ mark_as_advanced (MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES MBEDTLS_SSL_LIBRARY MBEDTLS_X509_LIBRARY MBEDTLS_CRYPTO_LIBRARY)
+
+endif (MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES AND MBEDTLS_VERSION)
diff --git a/dependencies/CMakeLists-mbedtls.txt.in b/dependencies/CMakeLists-mbedtls.txt.in
new file mode 100644
index 00000000..12888d5b
--- /dev/null
+++ b/dependencies/CMakeLists-mbedtls.txt.in
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(mbedtls)
+
+set(DOWNLOAD_DIR "@MBEDTLS_DOWNLOAD_DIR@")
+set(SOURCE_DIR "@MBEDTLS_SOURCE_DIR@")
+set(BINARY_DIR "@MBEDTLS_BINARY_DIR@")
+set(INSTALL_DIR "@MBEDTLS_INSTALL_DIR@")
+set(CMAKE_ARGS "@MBEDTLS_CMAKE_ARGS@")
+set(LOGGING "@MBEDTLS_LOGGING@")
+
+include(ExternalProject)
+
+ExternalProject_Add(
+ mbedtls
+ GIT_REPOSITORY "https://github.com/ARMmbed/mbedtls.git"
+ GIT_TAG origin/master
+ BUILD_ALWAYS OFF
+ DOWNLOAD_DIR "${DOWNLOAD_DIR}"
+ SOURCE_DIR "${SOURCE_DIR}"
+ BINARY_DIR "${BINARY_DIR}"
+ INSTALL_DIR "${INSTALL_DIR}"
+ CMAKE_ARGS ${CMAKE_ARGS}
+ CONFIGURE_COMMAND ""
+ UPDATE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD ${LOGGING}
+ LOG_UPDATE ${LOGGING}
+ LOG_PATCH ${LOGGING}
+ LOG_CONFIGURE ${LOGGING}
+ LOG_BUILD ${LOGGING}
+ LOG_INSTALL ${LOGGING}
+ LOG_TEST ${LOGGING}
+ LOG_MERGED_STDOUTERR ${LOGGING}
+ LOG_OUTPUT_ON_FAILURE ${LOGGING}
+)
diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt
index 2f143032..150c807b 100644
--- a/dependencies/CMakeLists.txt
+++ b/dependencies/CMakeLists.txt
@@ -58,7 +58,6 @@ endif()
message(STATUS "Using flatbuffers compiler: " ${FLATBUFFERS_FLATC_EXECUTABLE})
-
function(compile_flattbuffer_schema SRC_FBS OUTPUT_DIR)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
set_property(SOURCE ${GEN_HEADER} PROPERTY SKIP_AUTOMOC ON)
@@ -193,3 +192,132 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
set(${SRCS} ${${SRCS}} PARENT_SCOPE)
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction()
+
+#=============================================================================
+# MBEDTLS
+#=============================================================================
+
+set(USE_SYSTEM_MBEDTLS_LIBS ${DEFAULT_USE_SYSTEM_MBEDTLS_LIBS} CACHE BOOL "use mbedtls library from system")
+
+if (USE_SYSTEM_MBEDTLS_LIBS)
+ find_package(mbedtls REQUIRED)
+ if (NOT MBEDTLS_FOUND)
+ message(STATUS "Could NOT find mbedtls system libraries, build static mbedtls libraries")
+ #Fallback: build mbedtls static libray inside project
+ set(DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF PARENT_SCOPE)
+ set(USE_SYSTEM_MBEDTLS_LIBS OFF)
+ endif (NOT MBEDTLS_FOUND)
+endif (USE_SYSTEM_MBEDTLS_LIBS)
+
+if (NOT USE_SYSTEM_MBEDTLS_LIBS)
+ set(DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF CACHE BOOL "system mbedtls libraries not found, disable use system mbedtls libraries")
+ set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared mbedtls libraries")
+
+ set(ENABLE_TESTING OFF CACHE BOOL "Disable mbedTLS tests")
+ set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable mbedTLS programs")
+ set(USE_SHARED_MBEDTLS_LIBRARY OFF CACHE BOOL "Disable mbedTLS shared libraries")
+ set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "Enable mbedTLS static libraries")
+
+ set(MBEDTLS_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/download")
+ set(MBEDTLS_SOURCE_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/src")
+ set(MBEDTLS_BINARY_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/build")
+ set(MBEDTLS_INSTALL_DIR "${CMAKE_BINARY_DIR}")
+ if(${CMAKE_BUILD_TYPE} EQUAL "Debug")
+ set(MBEDTLS_LOGGING 1)
+ else ()
+ set(MBEDTLS_LOGGING 0)
+ endif ()
+
+ set(MBEDTLS_CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX:PATH=${MBEDTLS_INSTALL_DIR}
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DUSE_SHARED_MBEDTLS_LIBRARY:BOOL=OFF
+ -DUSE_STATIC_MBEDTLS_LIBRARY:BOOL=ON
+ -DENABLE_TESTING:BOOL=OFF
+ -DENABLE_PROGRAMS:BOOL=OFF
+ -DLINK_WITH_PTHREAD:BOOL=ON
+ -Wno-dev
+ #-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=TRUE
+ )
+
+ set(ENABLE_MBEDTLS_FETCH_CONTENT ON)
+
+ if (ENABLE_MBEDTLS_FETCH_CONTENT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.11)
+
+ include(FetchContent)
+
+ FetchContent_Declare(
+ mbedtls
+ GIT_REPOSITORY https://github.com/ARMmbed/mbedtls.git
+ GIT_TAG origin/master
+ BUILD_ALWAYS OFF
+ GIT_PROGRESS 1
+ DOWNLOAD_DIR "${MBEDTLS_DOWNLOAD_DIR}"
+ SOURCE_DIR "${MBEDTLS_SOURCE_DIR}"
+ BINARY_DIR "${MBEDTLS_BINARY_DIR}"
+ INSTALL_DIR "${MBEDTLS_INSTALL_DIR}"
+ CMAKE_ARGS ${MBEDTLS_CMAKE_ARGS}
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD ${MBEDTLS_LOGGING}
+ LOG_UPDATE ${MBEDTLS_LOGGING}
+ LOG_PATCH ${MBEDTLS_LOGGING}
+ LOG_CONFIGURE ${MBEDTLS_LOGGING}
+ LOG_BUILD ${MBEDTLS_LOGGING}
+ LOG_INSTALL ${MBEDTLS_LOGGING}
+ LOG_TEST ${MBEDTLS_LOGGING}
+ LOG_MERGED_STDOUTERR ${MBEDTLS_LOGGING}
+ LOG_OUTPUT_ON_FAILURE ${MBEDTLS_LOGGING}
+ )
+
+ if (CMAKE_VERSION VERSION_LESS 3.14)
+ macro (FetchContent_MakeAvailable NAME)
+ FetchContent_GetProperties(${NAME})
+ if (NOT ${NAME}_POPULATED)
+ FetchContent_Populate(${NAME})
+ add_subdirectory(${${NAME}_SOURCE_DIR} ${${NAME}_BINARY_DIR})
+ endif ()
+ endmacro ()
+ endif ()
+
+ FetchContent_MakeAvailable(mbedtls)
+ else ()
+ set(ENABLE_MBEDTLS_FETCH_CONTENT OFF PARENT_SCOPE)
+ if(NOT DEFINED BUILD_MBEDTLS_ONCE)
+ set(BUILD_MBEDTLS_ONCE CACHE INTERNAL "Done")
+ configure_file(${CMAKE_SOURCE_DIR}/dependencies/CMakeLists-mbedtls.txt.in ${MBEDTLS_DOWNLOAD_DIR}/CMakeLists.txt @ONLY)
+ execute_process(COMMAND ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX:PATH=${MBEDTLS_INSTALL_DIR} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${MBEDTLS_DOWNLOAD_DIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${MBEDTLS_DOWNLOAD_DIR})
+ add_subdirectory(${MBEDTLS_SOURCE_DIR} ${MBEDTLS_BINARY_DIR})
+ endif()
+ endif ()
+
+ set (MBEDTLS_INCLUDE_DIR "${MBEDTLS_SOURCE_DIR}/include")
+ set (MBEDTLS_INCLUDE_DIR ${MBEDTLS_INCLUDE_DIR} PARENT_SCOPE)
+ if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+ file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _MBEDTLS_VERSION_STRING REGEX "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
+ string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*" "\\1" MBEDTLS_VERSION "${_MBEDTLS_VERSION_STRING}")
+ message(STATUS "Using static mbedtls libraries (build version \"${MBEDTLS_VERSION}\")")
+ endif ()
+
+ include_directories(${MBEDTLS_INCLUDE_DIR})
+
+ if(WIN32)
+ set (MBEDTLS_LIB_INSTALL_DIR_WITH_LIB_PREFIX "${MBEDTLS_INSTALL_DIR}/lib/${CMAKE_CFG_INTDIR}/")
+ else()
+ set (MBEDTLS_LIB_INSTALL_DIR_WITH_LIB_PREFIX "${MBEDTLS_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}")
+ endif ()
+
+ set (MBEDTLS_SSL_LIBRARY "${MBEDTLS_LIB_INSTALL_DIR_WITH_LIB_PREFIX}mbedtls${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set (MBEDTLS_X509_LIBRARY "${MBEDTLS_LIB_INSTALL_DIR_WITH_LIB_PREFIX}mbedx509${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set (MBEDTLS_CRYPTO_LIBRARY "${MBEDTLS_LIB_INSTALL_DIR_WITH_LIB_PREFIX}mbedcrypto${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set (MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_X509_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY})
+ set (MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARIES} PARENT_SCOPE)
+
+ if(${CMAKE_BUILD_TYPE} EQUAL "Debug")
+ message(STATUS "mbedtls libraries: ${MBEDTLS_LIBRARIES}")
+ endif ()
+
+ mark_as_advanced (MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES MBEDTLS_SSL_LIBRARY MBEDTLS_X509_LIBRARY MBEDTLS_CRYPTO_LIBRARY)
+
+endif (NOT USE_SYSTEM_MBEDTLS_LIBS)
diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index 29e5e83a..186fe96a 100644
--- a/include/leddevice/LedDevice.h
+++ b/include/leddevice/LedDevice.h
@@ -177,13 +177,13 @@ protected:
/// Timer object which makes sure that led data is written at a minimum rate
/// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds
QTimer* _refresh_timer;
- int _refresh_timer_interval;
+ int _refresh_timer_interval;
/// timestamp of last write
qint64 _last_write_time;
/// Time a device requires mandatorily between two writes
- int _latchTime_ms;
+ int _latchTime_ms;
protected slots:
@@ -208,7 +208,7 @@ protected slots:
///
/// @param errorMsg The error message to be logged
///
- virtual void setInError( const QString& errorMsg);
+ virtual void setInError( const QString& errorMsg);
private:
diff --git a/include/ssdp/SSDPHandler.h b/include/ssdp/SSDPHandler.h
index 756b4dee..9eacaccc 100644
--- a/include/ssdp/SSDPHandler.h
+++ b/include/ssdp/SSDPHandler.h
@@ -22,6 +22,11 @@ public:
SSDPHandler(WebServer* webserver, const quint16& flatBufPort, const quint16& jsonServerPort, const QString &name, QObject * parent = nullptr);
~SSDPHandler();
+ ///
+ /// @brief Sends BYE BYE and stop server
+ ///
+ void stopServer();
+
public slots:
///
/// @brief Init SSDP after thread start
diff --git a/libsrc/hyperion/HyperionIManager.cpp b/libsrc/hyperion/HyperionIManager.cpp
index 0b5e319a..69429e17 100644
--- a/libsrc/hyperion/HyperionIManager.cpp
+++ b/libsrc/hyperion/HyperionIManager.cpp
@@ -196,7 +196,6 @@ void HyperionIManager::handleFinished()
hyperion->deleteLater();
emit instanceStateChanged(H_STOPPED, instance);
emit change();
-
}
void HyperionIManager::handleStarted()
diff --git a/libsrc/hyperion/MessageForwarder.cpp b/libsrc/hyperion/MessageForwarder.cpp
index 579c8587..a22d8366 100644
--- a/libsrc/hyperion/MessageForwarder.cpp
+++ b/libsrc/hyperion/MessageForwarder.cpp
@@ -111,9 +111,9 @@ void MessageForwarder::handlePriorityChanges(const quint8 &priority)
const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object();
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
{
- _flatSlaves.clear();
- while (!_forwardClients.isEmpty())
- delete _forwardClients.takeFirst();
+ //_flatSlaves.clear();
+ //while (!_forwardClients.isEmpty())
+ // delete _forwardClients.takeFirst();
hyperion::Components activeCompId = _hyperion->getPriorityInfo(priority).componentId;
if (activeCompId == hyperion::COMP_GRABBER || activeCompId == hyperion::COMP_V4L)
@@ -181,7 +181,7 @@ void MessageForwarder::addJsonSlave(QString slave)
return;
}
- if (_forwarder_enabled)
+ if (_forwarder_enabled && !_jsonSlaves.contains(slave))
_jsonSlaves << slave;
}
@@ -210,7 +210,7 @@ void MessageForwarder::addFlatbufferSlave(QString slave)
return;
}
- if (_forwarder_enabled)
+ if (_forwarder_enabled && !_flatSlaves.contains(slave))
{
_flatSlaves << slave;
FlatBufferConnection* flatbuf = new FlatBufferConnection("Forwarder", slave.toLocal8Bit().constData(), _priority, false);
diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt
index f1e5c392..f1054a24 100755
--- a/libsrc/leddevice/CMakeLists.txt
+++ b/libsrc/leddevice/CMakeLists.txt
@@ -87,7 +87,7 @@ target_link_libraries(leddevice
${CMAKE_THREAD_LIBS_INIT}
Qt5::Network
Qt5::SerialPort
- ssdp
+ ssdp
)
if(WIN32)
@@ -109,3 +109,11 @@ if (ENABLE_USB_HID)
target_link_libraries(leddevice ${LIBUSB_1_LIBRARIES} hidapi-libusb)
endif()
endif()
+
+if (NOT DEFAULT_USE_SYSTEM_MBEDTLS_LIBS)
+ if (MBEDTLS_LIBRARIES)
+ include_directories(${MBEDTLS_INCLUDE_DIR})
+ target_link_libraries(leddevice ${MBEDTLS_LIBRARIES})
+ target_include_directories(leddevice PRIVATE ${MBEDTLS_INCLUDE_DIR})
+ endif (MBEDTLS_LIBRARIES)
+endif ()
diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp
index 30191903..38456cb4 100644
--- a/libsrc/leddevice/LedDevice.cpp
+++ b/libsrc/leddevice/LedDevice.cpp
@@ -25,7 +25,7 @@ LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
, _latchTime_ms(0)
, _componentRegistered(false)
, _enabled(false)
- , _refresh_enabled (false)
+ , _refresh_enabled(false)
{
// setup refreshTimer
_refresh_timer->setTimerType(Qt::PreciseTimer);
@@ -74,7 +74,7 @@ void LedDevice::close()
void LedDevice::setEnable(bool enable)
{
- if (!_deviceReady && enable)
+ if ( !_deviceReady && enable )
{
Debug(_log, "Device '%s' was not ready! Trying to re-open.", QSTRING_CSTR(_activeDeviceType));
if ( open() < 0 )
@@ -90,19 +90,19 @@ void LedDevice::setEnable(bool enable)
}
// emit signal when state changed
- if (_enabled != enable)
+ if ( _enabled != enable )
{
emit enableStateChanged(enable);
}
// switch off device when disabled, default: set black to leds when they should go off
- if ( _enabled && !enable)
+ if ( _enabled && !enable )
{
switchOff();
}
else
{
// switch on device when enabled
- if ( !_enabled && enable)
+ if ( !_enabled && enable )
{
switchOn();
}
@@ -123,19 +123,18 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
_activeDeviceType = deviceConfig["type"].toString("file").toLower();
setLedCount(static_cast( deviceConfig["currentLedCount"].toInt(1) )); // property injected to reflect real led count
- _latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
- _refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
+ _latchTime_ms = deviceConfig["latchTime"].toInt( _latchTime_ms );
+ _refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
if ( _refresh_timer_interval > 0 )
{
_refresh_enabled = true;
- if (_refresh_timer_interval <= _latchTime_ms )
+ if ( _refresh_timer_interval <= _latchTime_ms )
{
int new_refresh_timer_interval = _latchTime_ms + 10;
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refresh_timer_interval, new_refresh_timer_interval);
_refresh_timer_interval = new_refresh_timer_interval;
- _refresh_timer->setInterval( _refresh_timer_interval );
}
//Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
@@ -150,7 +149,7 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
void LedDevice::startRefreshTimer()
{
- if ( _deviceReady)
+ if ( _deviceReady )
{
_refresh_timer->start();
}
@@ -164,7 +163,7 @@ void LedDevice::stopRefreshTimer()
int LedDevice::updateLeds(const std::vector& ledValues)
{
int retval = 0;
- if ( !_deviceReady || _deviceInError)
+ if ( !_deviceReady || _deviceInError )
{
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
return -1;
@@ -243,8 +242,8 @@ int LedDevice::rewriteLeds()
if ( _deviceReady )
{
- //qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
- //std::cout << "LedDevice::rewriteLeds(): Rewrite Leds now, elapsedTime [" << elapsedTime << "] ms" << std::endl;
+// qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
+// std::cout << "LedDevice::rewriteLeds(): Rewrite Leds now, elapsedTime [" << elapsedTime << "] ms" << std::endl;
// //:TESTING: Inject "white" output records to differentiate from normal writes
// _last_ledValues.clear();
// _last_ledValues.resize(static_cast(_ledCount), ColorRgb::WHITE);
@@ -262,7 +261,7 @@ int LedDevice::rewriteLeds()
return retval;
}
-void LedDevice::printLedValues(const std::vector& ledValues )
+void LedDevice::printLedValues(const std::vector& ledValues)
{
std::cout << "LedValues [" << ledValues.size() <<"] [";
for (const ColorRgb& color : ledValues)
diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
index e51e35ac..665c2b6c 100644
--- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
@@ -428,8 +428,6 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
return jsonDoc;
}
-
-
int LedDeviceNanoleaf::write(const std::vector & ledValues)
{
diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
index 8a5d3064..1748d826 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
@@ -4,24 +4,30 @@
// ssdp discover
#include
-// Qt includes
-#include
-#include
-#include
-
-//
-static const bool verbose = false;
-static const bool verbose3 = false;
+bool verbose = false;
// Configuration settings
static const char CONFIG_ADDRESS[] = "output";
//static const char CONFIG_PORT[] = "port";
-static const char CONFIG_USERNAME[] ="username";
-static const char CONFIG_BRIGHTNESSFACTOR [] = "brightnessFactor";
-static const char CONFIG_TRANSITIONTIME [] = "transitiontime";
-static const char CONFIG_ON_OFF_BLACK [] = "switchOffOnBlack";
-static const char CONFIG_RESTORE_STATE [] = "restoreOriginalState";
-static const char CONFIG_LIGHTIDS [] = "lightIds";
+static const char CONFIG_USERNAME[] = "username";
+static const char CONFIG_CLIENTKEY[] = "clientkey";
+static const char CONFIG_BRIGHTNESSFACTOR[] = "brightnessFactor";
+static const char CONFIG_TRANSITIONTIME[] = "transitiontime";
+static const char CONFIG_BLACK_LIGHTS_TIMEOUT[] = "blackLightsTimeout";
+static const char CONFIG_ON_OFF_BLACK[] = "switchOffOnBlack";
+static const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
+static const char CONFIG_LIGHTIDS[] = "lightIds";
+static const char CONFIG_USE_HUE_ENTERTAINMENT_API[] = "useEntertainmentAPI";
+static const char CONFIG_GROUPID[] = "groupId";
+
+static const char CONFIG_VERBOSE[] = "verbose";
+static const char CONFIG_BRIGHTNESS_MIN[] = "brightnessMin";
+static const char CONFIG_BRIGHTNESS_MAX[] = "brightnessMax";
+static const char CONFIG_BRIGHTNESS_THRESHOLD[] = "brightnessThreshold";
+
+static const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN[] = "sslHSTimeoutMin";
+static const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX[] = "sslHSTimeoutMax";
+static const char CONFIG_SSL_READ_TIMEOUT[] = "sslReadTimeout";
// Device Data elements
static const char DEV_DATA_BRIDGEID[] = "bridgeid";
@@ -35,9 +41,21 @@ static const char DEV_DATA_APIVERSION[] = "apiversion";
static const char API_DEFAULT_PORT[] = "80";
static const char API_URL_FORMAT[] = "http://%1:%2/api/%3/%4";
static const char API_ROOT[] = "";
-static const char API_STATE[] ="state";
+static const char API_STATE[] = "state";
static const char API_CONFIG[] = "config";
static const char API_LIGHTS[] = "lights";
+static const char API_GROUPS[] = "groups";
+
+// List of Group / Stream Information
+static const char API_GROUP_NAME[] = "name";
+static const char API_GROUP_TYPE[] = "type";
+static const char API_GROUP_TYPE_ENTERTAINMENT[] = "Entertainment";
+static const char API_STREAM[] = "stream";
+static const char API_STREAM_ACTIVE[] = "active";
+static const char API_STREAM_ACTIVE_VALUE_TRUE[] = "true";
+static const char API_STREAM_ACTIVE_VALUE_FALSE[] = "false";
+static const char API_STREAM_OWNER[] = "owner";
+static const char API_STREAM_RESPONSE_FORMAT[] = "/%1/%2/%3/%4";
// List of resources
static const char API_XY_COORDINATES[] = "xy";
@@ -54,12 +72,26 @@ static const char API_STATE_VALUE_FALSE[] = "false";
static const char API_ERROR[] = "error";
static const char API_ERROR_ADDRESS[] = "address";
static const char API_ERROR_DESCRIPTION[] = "description";
-static const char API_ERROR_TYPE[]="type";
+static const char API_ERROR_TYPE[] = "type";
+
+// List of Success Information
+static const char API_SUCCESS[] = "success";
// Phlips Hue ssdp services
static const char SSDP_ID[] = "urn:schemas-upnp-org:device:Basic:1";
const int SSDP_TIMEOUT = 5000; // timout in ms
+// DTLS Connection / SSL / Cipher Suite
+static const char API_SSL_SERVER_NAME[] = "Hue";
+static const char API_SSL_SEED_CUSTOM[] = "dtls_client";
+const int API_SSL_SERVER_PORT = 2100;
+const int STREAM_CONNECTION_RETRYS = 5;
+const int STREAM_REWRITE_TIME = 20;
+const int STREAM_SSL_HANDSHAKE_ATTEMPTS = 5;
+const int STREAM_SSL_HANDSHAKE_TIMEOUT_MIN = 400;
+const int STREAM_SSL_HANDSHAKE_TIMEOUT_MAX = 1000;
+const int STREAM_SSL_READ_TIMEOUT = 0;
+const int SSL_CIPHERSUITES[2] = { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, 0 };
bool operator ==(const CiColor& p1, const CiColor& p2)
{
@@ -71,7 +103,7 @@ bool operator != (const CiColor& p1, const CiColor& p2)
return !(p1 == p2);
}
-CiColor CiColor::rgbToCiColor(double red, double green, double blue, CiColorTriangle colorSpace)
+CiColor CiColor::rgbToCiColor(double red, double green, double blue, const CiColorTriangle &colorSpace)
{
double cx;
double cy;
@@ -79,7 +111,6 @@ CiColor CiColor::rgbToCiColor(double red, double green, double blue, CiColorTria
if(red + green + blue > 0)
{
-
// Apply gamma correction.
double r = (red > 0.04045) ? pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);
double g = (green > 0.04045) ? pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);
@@ -126,15 +157,15 @@ CiColor CiColor::rgbToCiColor(double red, double green, double blue, CiColorTria
if (!isPointInLampsReach(xy, colorSpace))
{
// It seems the color is out of reach let's find the closes color we can produce with our lamp and send this XY value out.
- CiColor pAB = getClosestPointToPoint(colorSpace.red, colorSpace.green, xy);
- CiColor pAC = getClosestPointToPoint(colorSpace.blue, colorSpace.red, xy);
- CiColor pBC = getClosestPointToPoint(colorSpace.green, colorSpace.blue, xy);
+ XYColor pAB = getClosestPointToPoint(colorSpace.red, colorSpace.green, xy);
+ XYColor pAC = getClosestPointToPoint(colorSpace.blue, colorSpace.red, xy);
+ XYColor pBC = getClosestPointToPoint(colorSpace.green, colorSpace.blue, xy);
// Get the distances per point and see which point is closer to our Point.
double dAB = getDistanceBetweenTwoPoints(xy, pAB);
double dAC = getDistanceBetweenTwoPoints(xy, pAC);
double dBC = getDistanceBetweenTwoPoints(xy, pBC);
double lowest = dAB;
- CiColor closestPoint = pAB;
+ XYColor closestPoint = pAB;
if (dAC < lowest)
{
lowest = dAC;
@@ -153,44 +184,44 @@ CiColor CiColor::rgbToCiColor(double red, double green, double blue, CiColorTria
return xy;
}
-double CiColor::crossProduct(CiColor p1, CiColor p2)
+double CiColor::crossProduct(XYColor p1, XYColor p2)
{
return p1.x * p2.y - p1.y * p2.x;
}
-bool CiColor::isPointInLampsReach(CiColor p, CiColorTriangle colorSpace)
+bool CiColor::isPointInLampsReach(CiColor p, const CiColorTriangle &colorSpace)
{
- CiColor v1 = { colorSpace.green.x - colorSpace.red.x, colorSpace.green.y - colorSpace.red.y };
- CiColor v2 = { colorSpace.blue.x - colorSpace.red.x, colorSpace.blue.y - colorSpace.red.y };
- CiColor q = { p.x - colorSpace.red.x, p.y - colorSpace.red.y };
+ XYColor v1 = { colorSpace.green.x - colorSpace.red.x, colorSpace.green.y - colorSpace.red.y };
+ XYColor v2 = { colorSpace.blue.x - colorSpace.red.x, colorSpace.blue.y - colorSpace.red.y };
+ XYColor q = { p.x - colorSpace.red.x, p.y - colorSpace.red.y };
double s = crossProduct(q, v2) / crossProduct(v1, v2);
double t = crossProduct(v1, q) / crossProduct(v1, v2);
- if ((s >= 0.0) && (t >= 0.0) && (s + t <= 1.0))
+ if ( ( s >= 0.0 ) && ( t >= 0.0 ) && ( s + t <= 1.0 ) )
{
return true;
}
return false;
}
-CiColor CiColor::getClosestPointToPoint(CiColor a, CiColor b, CiColor p)
+XYColor CiColor::getClosestPointToPoint(XYColor a, XYColor b, CiColor p)
{
- CiColor AP = { p.x - a.x, p.y - a.y };
- CiColor AB = { b.x - a.x, b.y - a.y };
+ XYColor AP = { p.x - a.x, p.y - a.y };
+ XYColor AB = { b.x - a.x, b.y - a.y };
double ab2 = AB.x * AB.x + AB.y * AB.y;
double ap_ab = AP.x * AB.x + AP.y * AB.y;
double t = ap_ab / ab2;
- if (t < 0.0)
+ if ( t < 0.0 )
{
t = 0.0;
}
- else if (t > 1.0)
+ else if ( t > 1.0 )
{
t = 1.0;
}
return { a.x + AB.x * t, a.y + AB.y * t };
}
-double CiColor::getDistanceBetweenTwoPoints(CiColor p1, CiColor p2)
+double CiColor::getDistanceBetweenTwoPoints(CiColor p1, XYColor p2)
{
// Horizontal difference.
double dx = p1.x - p2.x;
@@ -201,12 +232,13 @@ double CiColor::getDistanceBetweenTwoPoints(CiColor p1, CiColor p2)
}
LedDevicePhilipsHueBridge::LedDevicePhilipsHueBridge(const QJsonObject &deviceConfig)
- : LedDevice(deviceConfig)
- , _networkmanager (nullptr)
+ : ProviderUdpSSL()
+ , _useHueEntertainmentAPI(false)
+ , _networkmanager(nullptr)
, _api_major(0)
, _api_minor(0)
, _api_patch(0)
- , _isHueEntertainmentReady (false)
+ , _isHueEntertainmentReady(false)
{
_devConfig = deviceConfig;
_deviceReady = false;
@@ -214,7 +246,7 @@ LedDevicePhilipsHueBridge::LedDevicePhilipsHueBridge(const QJsonObject &deviceCo
LedDevicePhilipsHueBridge::~LedDevicePhilipsHueBridge()
{
- if (_networkmanager != nullptr)
+ if ( _networkmanager != nullptr )
{
delete _networkmanager;
_networkmanager = nullptr;
@@ -223,54 +255,56 @@ LedDevicePhilipsHueBridge::~LedDevicePhilipsHueBridge()
bool LedDevicePhilipsHueBridge::init(const QJsonObject &deviceConfig)
{
+ _useHueEntertainmentAPI = deviceConfig[CONFIG_USE_HUE_ENTERTAINMENT_API].toBool(false);
+
// Overwrite non supported/required features
- _devConfig["latchTime"] = 0;
- if (deviceConfig["rewriteTime"].toInt(0) > 0)
+ _devConfig["latchTime"] = 0;
+ if ( deviceConfig["rewriteTime"].toInt(0) > 0 )
{
- Info (_log, "Device Philips Hue does not require rewrites. Refresh time is ignored.");
+ InfoIf ( ( !_useHueEntertainmentAPI ), _log, "Device Philips Hue does not require rewrites. Refresh time is ignored." );
_devConfig["rewriteTime"] = 0;
}
- DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ DebugIf( verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
bool isInitOK = LedDevice::init(deviceConfig);
- Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
- Debug(_log, "LedCount : %u", this->getLedCount());
- Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
- Debug(_log, "RefreshTime : %d", _refresh_timer_interval);
- Debug(_log, "LatchTime : %d", this->getLatchTime());
+ log( "DeviceType", "%s", QSTRING_CSTR( this->getActiveDeviceType() ) );
+ log( "LedCount", "%u", this->getLedCount() );
+ log( "ColorOrder", "%s", QSTRING_CSTR( this->getColorOrder() ) );
+ log( "RefreshTime", "%d", _refresh_timer_interval );
+ log( "LatchTime", "%d", this->getLatchTime() );
if ( isInitOK )
{
//Set hostname as per configuration and_defaultHost default port
QString address = deviceConfig[ CONFIG_ADDRESS ].toString();
- if (! address.isEmpty() )
+ if ( !address.isEmpty() )
{
QStringList addressparts = address.split(":", QString::SkipEmptyParts);
_hostname = addressparts[0];
- if ( addressparts.size() > 1)
+ if ( addressparts.size() > 1 )
{
_api_port = addressparts[1];
}
else
{
- _api_port = API_DEFAULT_PORT;
+ _api_port = API_DEFAULT_PORT;
}
}
_username = deviceConfig[ CONFIG_USERNAME ].toString();
- Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
- Debug(_log, "Port : %s", QSTRING_CSTR( _api_port ));
+ log( "Hostname/IP", "%s", QSTRING_CSTR( _hostname ) );
+ log( "Port", "%s", QSTRING_CSTR( _api_port ) );
}
return isInitOK;
}
-int LedDevicePhilipsHueBridge::open( )
+int LedDevicePhilipsHueBridge::open()
{
- return open (_hostname,_api_port, _username );
+ return open( _hostname, _api_port, _username );
}
int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& port, const QString& username )
@@ -281,10 +315,10 @@ int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& por
//If host not configured then discover device
if ( hostname.isEmpty() )
{
- //Discover Nanoleaf device
+ //Discover Philips Hue Bridge device
if ( !discoverDevice() )
{
- this->setInError("No target IP defined nor Philips Hue Bridge was discovered");
+ this->setInError( "No target IP defined nor Philips Hue Bridge was discovered" );
return false;
}
}
@@ -296,16 +330,49 @@ int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& por
_username = username;
//Get Philips Hue Bridge details and configuration
- if ( _networkmanager == nullptr)
+ if ( _networkmanager == nullptr )
{
_networkmanager = new QNetworkAccessManager();
}
- // Read Lights and Light-Ids
- QString url = getUrl(_hostname, _api_port, _username, API_ROOT );
- QJsonDocument doc = getJson( url );
+ isInitOK = initMaps();
- DebugIf(verbose, _log, "doc: [%s]", QString(QJsonDocument(doc).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ return isInitOK;
+}
+
+const int *LedDevicePhilipsHueBridge::getCiphersuites()
+{
+ return SSL_CIPHERSUITES;
+}
+
+void LedDevicePhilipsHueBridge::log(const char* msg, const char* type, ...)
+{
+ const size_t max_val_length = 1024;
+ char val[max_val_length];
+ va_list args;
+ va_start(args, type);
+ vsnprintf(val, max_val_length, type, args);
+ va_end(args);
+ std::string s = msg;
+ int max = 30;
+ s.append(max - s.length(), ' ');
+ Debug( _log, "%s: %s", s.c_str(), val );
+}
+
+QJsonDocument LedDevicePhilipsHueBridge::getAllBridgeInfos()
+{
+ // Read Groups/ Lights and Light-Ids
+ QString url = getUrl( _hostname, _api_port, _username, API_ROOT );
+ return getJson( url );
+}
+
+bool LedDevicePhilipsHueBridge::initMaps()
+{
+ bool isInitOK = true;
+
+ QJsonDocument doc = getAllBridgeInfos();
+
+ DebugIf( verbose, _log, "doc: [%s]", QString(QJsonDocument(doc).toJson(QJsonDocument::Compact)).toUtf8().constData() );
if ( this->isInError() )
{
@@ -313,83 +380,118 @@ int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& por
}
else
{
- QJsonObject jsonConfigInfo = doc.object()[API_CONFIG].toObject();
- if ( verbose )
+ setBridgeConfig( doc );
+ if( _useHueEntertainmentAPI ) setGroupMap( doc );
+ setLightsMap( doc );
+ }
+
+ return isInitOK;
+}
+
+void LedDevicePhilipsHueBridge::setBridgeConfig(QJsonDocument doc)
+{
+ QJsonObject jsonConfigInfo = doc.object()[ API_CONFIG ].toObject();
+ if ( verbose )
+ {
+ std::cout << "jsonConfigInfo: [" << QString(QJsonDocument(jsonConfigInfo).toJson(QJsonDocument::Compact)).toUtf8().constData() << "]" << std::endl;
+ }
+
+ QString deviceName = jsonConfigInfo[DEV_DATA_NAME].toString();
+ _deviceModel = jsonConfigInfo[DEV_DATA_MODEL].toString();
+ QString deviceBridgeID = jsonConfigInfo[DEV_DATA_BRIDGEID].toString();
+ _deviceFirmwareVersion = jsonConfigInfo[DEV_DATA_FIRMWAREVERSION].toString();
+ _deviceAPIVersion = jsonConfigInfo[DEV_DATA_APIVERSION].toString();
+
+ QStringList apiVersionParts = _deviceAPIVersion.split(".", QString::SkipEmptyParts);
+ if ( !apiVersionParts.isEmpty() )
+ {
+ _api_major = apiVersionParts[0].toUInt();
+ _api_minor = apiVersionParts[1].toUInt();
+ _api_patch = apiVersionParts[2].toUInt();
+
+ if ( _api_major > 1 || (_api_major == 1 && _api_minor >= 22) )
{
- std::cout << "jsonConfigInfo: [" << QString(QJsonDocument(jsonConfigInfo).toJson(QJsonDocument::Compact)).toUtf8().constData() << "]" << std::endl;
- }
-
- QString deviceName = jsonConfigInfo[DEV_DATA_NAME].toString();
- _deviceModel = jsonConfigInfo[DEV_DATA_MODEL].toString();
- QString deviceBridgeID = jsonConfigInfo[DEV_DATA_BRIDGEID].toString();
- _deviceFirmwareVersion = jsonConfigInfo[DEV_DATA_FIRMWAREVERSION].toString();
- _deviceAPIVersion = jsonConfigInfo[DEV_DATA_APIVERSION].toString();
-
- QStringList apiVersionParts = _deviceAPIVersion.split(".", QString::SkipEmptyParts);
- if ( !apiVersionParts.isEmpty())
- {
- _api_major = apiVersionParts[0].toUInt();
- _api_minor = apiVersionParts[1].toUInt();
- _api_patch = apiVersionParts[2].toUInt();
-
- if ( _api_major > 1 || (_api_major == 1 && _api_minor >= 22) )
- {
- _isHueEntertainmentReady = true;
- }
- }
-
- Debug(_log, "Bridge Name : %s", QSTRING_CSTR( deviceName ));
- Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
- Debug(_log, "Bridge-ID : %s", QSTRING_CSTR( deviceBridgeID ));
- Debug(_log, "SoftwareVersion : %s", QSTRING_CSTR( _deviceFirmwareVersion));
- Debug(_log, "API-Version : %u.%u.%u", _api_major,_api_minor, _api_patch );
- Debug(_log, "EntertainmentReady: %d", _isHueEntertainmentReady);
-
- QJsonObject jsonLightsInfo = doc.object()[API_LIGHTS].toObject();
-
- DebugIf(verbose, _log, "jsonLightsInfo: [%s]", QString(QJsonDocument(jsonLightsInfo).toJson(QJsonDocument::Compact)).toUtf8().constData() );
-
- // Get all available light ids and their values
- QStringList keys = jsonLightsInfo.keys();
-
- _ledCount = keys.size();
- _lightsMap.clear();
-
- for (uint i = 0; i < _ledCount; ++i)
- {
- _lightsMap.insert(keys.at(i).toInt(), jsonLightsInfo.take(keys.at(i)).toObject());
- }
-
- if (getLedCount() == 0 )
- {
- setInError("No light-IDs found at the Philips Hue Bridge");
- }
- else
- {
- Debug(_log, "Lights found : %u", getLedCount() );
+ _isHueEntertainmentReady = true;
}
}
- return isInitOK;
+
+ if( _useHueEntertainmentAPI )
+ {
+ DebugIf( !_isHueEntertainmentReady, _log, "Bridge is not Entertainment API Ready - Entertainment API usage was disabled!" );
+ _useHueEntertainmentAPI = _isHueEntertainmentReady;
+ }
+
+ log( "Bridge Name", "%s", QSTRING_CSTR( deviceName ));
+ log( "Model", "%s", QSTRING_CSTR( _deviceModel ));
+ log( "Bridge-ID", "%s", QSTRING_CSTR( deviceBridgeID ));
+ log( "SoftwareVersion", "%s", QSTRING_CSTR( _deviceFirmwareVersion ));
+ log( "API-Version", "%u.%u.%u", _api_major, _api_minor, _api_patch );
+ log( "EntertainmentReady", "%d", _isHueEntertainmentReady );
+}
+
+void LedDevicePhilipsHueBridge::setLightsMap(QJsonDocument doc)
+{
+ QJsonObject jsonLightsInfo = doc.object()[ API_LIGHTS ].toObject();
+
+ DebugIf(verbose, _log, "jsonLightsInfo: [%s]", QString(QJsonDocument(jsonLightsInfo).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ // Get all available light ids and their values
+ QStringList keys = jsonLightsInfo.keys();
+
+ _ledCount = keys.size();
+ _lightsMap.clear();
+
+ for ( unsigned int i = 0; i < _ledCount; ++i )
+ {
+ _lightsMap.insert(keys.at(i).toUInt(), jsonLightsInfo.take(keys.at(i)).toObject());
+ }
+
+ if ( getLedCount() == 0 )
+ {
+ this->setInError( "No light-IDs found at the Philips Hue Bridge" );
+ }
+ else
+ {
+ log( "Lights in Bridge found", "%u", getLedCount() );
+ }
+}
+
+void LedDevicePhilipsHueBridge::setGroupMap(QJsonDocument doc)
+{
+ QJsonObject jsonGroupsInfo = doc.object()[ API_GROUPS ].toObject();
+
+ DebugIf(verbose, _log, "jsonGroupsInfo: [%s]", QString(QJsonDocument(jsonGroupsInfo).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ // Get all available group ids and their values
+ QStringList keys = jsonGroupsInfo.keys();
+
+ unsigned int _groupsCount = keys.size();
+ _groupsMap.clear();
+
+ for ( unsigned int i = 0; i < _groupsCount; ++i )
+ {
+ _groupsMap.insert( keys.at(i).toUInt(), jsonGroupsInfo.take(keys.at(i)).toObject() );
+ }
}
bool LedDevicePhilipsHueBridge::discoverDevice()
{
- bool isDeviceFound (false);
+ bool isDeviceFound( false );
// device searching by ssdp
QString address;
SSDPDiscover discover;
// Discover Philips Hue Bridge
- address = discover.getFirstService(STY_WEBSERVER, SSDP_ID, SSDP_TIMEOUT);
+ address = discover.getFirstService( STY_WEBSERVER, SSDP_ID, SSDP_TIMEOUT );
if ( address.isEmpty() )
{
- Warning(_log, "No Philips Hue Bridge discovered");
+ Warning(_log, "No Philips Hue Bridge discovered" );
}
else
{
// Philips Hue Bridge found
- Info(_log, "Philips Hue Bridge discovered at [%s]", QSTRING_CSTR( address ));
+ Info(_log, "Philips Hue Bridge discovered at [%s]", QSTRING_CSTR( address ) );
isDeviceFound = true;
QStringList addressparts = address.split(":", QString::SkipEmptyParts);
_hostname = addressparts[0];
@@ -403,13 +505,62 @@ const QMap& LedDevicePhilipsHueBridge::getLightMap(void)
return _lightsMap;
}
+const QMap& LedDevicePhilipsHueBridge::getGroupMap(void)
+{
+ return _groupsMap;
+}
+
+QString LedDevicePhilipsHueBridge::getGroupName(unsigned int groupId)
+{
+ QString groupName;
+ if( _groupsMap.contains( groupId ) )
+ {
+ QJsonObject group = _groupsMap.value( groupId );
+ groupName = group.value( API_GROUP_NAME ).toString().trimmed().replace("\"", "");
+ }
+ else
+ {
+ Error(_log, "Group ID %d doesn't exists on this bridge", groupId );
+ }
+ return groupName;
+}
+
+QJsonArray LedDevicePhilipsHueBridge::getGroupLights(unsigned int groupId)
+{
+ QJsonArray groupLights;
+ // search user groupid inside _groupsMap and create light if found
+ if( _groupsMap.contains( groupId ) )
+ {
+ QJsonObject group = _groupsMap.value( groupId );
+
+ if( group.value( API_GROUP_TYPE ) == API_GROUP_TYPE_ENTERTAINMENT )
+ {
+ QString groupName = getGroupName( groupId );
+ groupLights = group.value( API_LIGHTS ).toArray();
+
+ log( "Entertainment Group found", "[%d] %s", groupId, QSTRING_CSTR(groupName) );
+ log( "Lights in Group", "%d", groupLights.size() );
+ Info(_log, "Entertainment Group [%d] \"%s\" with %d Lights found", groupId, QSTRING_CSTR(groupName), groupLights.size() );
+ }
+ else
+ {
+ Error(_log, "Group ID %d is not an entertainment group", groupId );
+ }
+ }
+ else
+ {
+ Error(_log, "Group ID %d doesn't exists on this bridge", groupId );
+ }
+
+ return groupLights;
+}
+
QString LedDevicePhilipsHueBridge::getUrl(QString host, QString port, QString auth_token, QString endpoint) const {
- return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
+ return QString(API_URL_FORMAT).arg( host, port, auth_token, endpoint );
}
QJsonDocument LedDevicePhilipsHueBridge::getJson(QString url)
{
-
DebugIf(verbose, _log, "GET: [%s]", QSTRING_CSTR( url ));
// Perfrom request
@@ -422,7 +573,7 @@ QJsonDocument LedDevicePhilipsHueBridge::getJson(QString url)
loop.exec();
QJsonDocument jsonDoc;
- if(reply->operation() == QNetworkAccessManager::GetOperation)
+ if( reply->operation() == QNetworkAccessManager::GetOperation )
{
jsonDoc = handleReply( reply );
}
@@ -434,11 +585,10 @@ QJsonDocument LedDevicePhilipsHueBridge::getJson(QString url)
QJsonDocument LedDevicePhilipsHueBridge::putJson(QString url, QString json)
{
-
DebugIf(verbose, _log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
// Perfrom request
- QNetworkRequest request(url);
- QNetworkReply* reply = _networkmanager->put(request, json.toUtf8());
+ QNetworkRequest request( url );
+ QNetworkReply* reply = _networkmanager->put( request, json.toUtf8() );
// Connect requestFinished signal to quit slot of the loop.
QEventLoop loop;
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
@@ -446,13 +596,12 @@ QJsonDocument LedDevicePhilipsHueBridge::putJson(QString url, QString json)
loop.exec();
QJsonDocument jsonDoc;
- if(reply->operation() == QNetworkAccessManager::PutOperation)
+ if( reply->operation() == QNetworkAccessManager::PutOperation )
{
jsonDoc = handleReply( reply );
}
// Free space.
reply->deleteLater();
-
// Return response
return jsonDoc;
}
@@ -465,15 +614,16 @@ QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply
DebugIf(verbose, _log, "Reply.httpStatusCode [%d]", httpStatusCode );
QString errorReason;
- if(reply->error() == QNetworkReply::NoError)
+ if( reply->error() == QNetworkReply::NoError )
{
- if ( httpStatusCode != 204 ){
+ if ( httpStatusCode != 204 )
+ {
QByteArray response = reply->readAll();
QJsonParseError error;
jsonDoc = QJsonDocument::fromJson(response, &error);
- if (error.error != QJsonParseError::NoError)
+ if ( error.error != QJsonParseError::NoError )
{
- this->setInError ( "Got invalid response" );
+ this->setInError( "Got invalid response" );
}
else
{
@@ -484,19 +634,22 @@ QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply
if ( !rspList.isEmpty() )
{
QVariantMap map = rspList.first().toMap();
- if ( map.contains(API_ERROR) )
+ if ( map.contains( API_ERROR ) )
{
// API call failsed to execute an error message was returned
QString errorAddress = map.value(API_ERROR).toMap().value(API_ERROR_ADDRESS).toString();
QString errorDesc = map.value(API_ERROR).toMap().value(API_ERROR_DESCRIPTION).toString();
QString errorType = map.value(API_ERROR).toMap().value(API_ERROR_TYPE).toString();
- Debug(_log, "Error Type : %s", QSTRING_CSTR( errorType ));
- Debug(_log, "Error Address : %s", QSTRING_CSTR( errorAddress ));
- Debug(_log, "Error Description : %s", QSTRING_CSTR( errorDesc ));
+ log( "Error Type", "%s", QSTRING_CSTR( errorType ) );
+ log( "Error Address", "%s", QSTRING_CSTR( errorAddress ) );
+ log( "Error Address Description", "%s", QSTRING_CSTR( errorDesc ) );
- errorReason = QString ("(%1) %2, Resource:%3").arg(errorType, errorDesc, errorAddress);
- this->setInError ( errorReason );
+ if( errorType != "901" )
+ {
+ errorReason = QString ("(%1) %2, Resource:%3").arg(errorType, errorDesc, errorAddress);
+ this->setInError( errorReason );
+ }
}
}
}
@@ -504,7 +657,8 @@ QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply
}
else
{
- if ( httpStatusCode > 0 ) {
+ if ( httpStatusCode > 0 )
+ {
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
QString advise;
switch ( httpStatusCode ) {
@@ -520,27 +674,45 @@ QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply
default:
break;
}
- errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason, advise);
+ errorReason = QString( "%1:%2 [%3 %4] - %5").arg( _hostname, _api_port, QString(httpStatusCode), httpReason, advise );
}
- else {
- errorReason = QString ("%1:%2 - %3").arg(_hostname, _api_port, reply->errorString());
+ else
+ {
+ errorReason = QString( "%1:%2 - %3").arg( _hostname, _api_port, reply->errorString() );
}
- this->setInError ( errorReason );
+ this->setInError( errorReason );
}
// Return response
return jsonDoc;
}
-void LedDevicePhilipsHueBridge::post(const QString& route, const QString& content)
+QJsonDocument LedDevicePhilipsHueBridge::post(const QString& route, const QString& content)
{
QString url = getUrl(_hostname, _api_port, _username, route );
- putJson( url, content );
+ return putJson( url, content );
}
void LedDevicePhilipsHueBridge::setLightState(const unsigned int lightId, QString state)
{
- Debug(_log, "SetLightState [%u]: %s", lightId, QSTRING_CSTR(state));
- post( QString("%1/%2/%3").arg(API_LIGHTS).arg(lightId).arg(API_STATE), state );
+ DebugIf( verbose, _log, "SetLightState [%u]: %s", lightId, QSTRING_CSTR(state) );
+ post( QString("%1/%2/%3").arg( API_LIGHTS ).arg( lightId ).arg( API_STATE ), state );
+}
+
+QJsonDocument LedDevicePhilipsHueBridge::getGroupState(const unsigned int groupId)
+{
+ QString url = getUrl( _hostname, _api_port, _username, QString("%1/%2").arg( API_GROUPS ).arg( groupId ) );
+ return getJson( url );
+}
+
+QJsonDocument LedDevicePhilipsHueBridge::setGroupState(const unsigned int groupId, bool state)
+{
+ QString active = state ? API_STREAM_ACTIVE_VALUE_TRUE : API_STREAM_ACTIVE_VALUE_FALSE;
+ return post( QString("%1/%2").arg( API_GROUPS ).arg( groupId ), QString("{\"%1\":{\"%2\":%3}}").arg( API_STREAM ).arg( API_STREAM_ACTIVE ).arg( active ) );
+}
+
+bool LedDevicePhilipsHueBridge::isStreamOwner(const QString streamOwner)
+{
+ return ( streamOwner != "" && streamOwner == _username );
}
const std::set PhilipsHueLight::GAMUT_A_MODEL_IDS =
@@ -548,7 +720,7 @@ const std::set PhilipsHueLight::GAMUT_A_MODEL_IDS =
const std::set PhilipsHueLight::GAMUT_B_MODEL_IDS =
{ "LCT001", "LCT002", "LCT003", "LCT007", "LLM001" };
const std::set PhilipsHueLight::GAMUT_C_MODEL_IDS =
- { "LLC020", "LST002", "LCT011", "LCT012", "LCT010", "LCT014", "LCT015", "LCT016", "LCT024" };
+ { "LCA001", "LCA002", "LCA003", "LCG002", "LCP001", "LCP002", "LCT010", "LCT011", "LCT012", "LCT014", "LCT015", "LCT016", "LCT024", "LLC020", "LST002" };
PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject values, unsigned int ledidx)
: _log(log)
@@ -557,12 +729,12 @@ PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject value
, _on(false)
, _transitionTime(0)
, _colorBlack({0.0, 0.0, 0.0})
- , _modelId (values[API_MODEID].toString().trimmed().replace("\"", ""))
+ , _modelId(values[API_MODEID].toString().trimmed().replace("\"", ""))
{
// Find id in the sets and set the appropriate color space.
if (GAMUT_A_MODEL_IDS.find(_modelId) != GAMUT_A_MODEL_IDS.end())
{
- Debug(_log, "Recognized model id %s of light ID %d as gamut A", QSTRING_CSTR(_modelId), id);
+ Debug(_log, "Recognized model id %s of light ID %d as gamut A", QSTRING_CSTR(_modelId), id );
_colorSpace.red = {0.704, 0.296};
_colorSpace.green = {0.2151, 0.7106};
_colorSpace.blue = {0.138, 0.08};
@@ -570,7 +742,7 @@ PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject value
}
else if (GAMUT_B_MODEL_IDS.find(_modelId) != GAMUT_B_MODEL_IDS.end())
{
- Debug(_log, "Recognized model id %s of light ID %d as gamut B", QSTRING_CSTR(_modelId), id);
+ Debug(_log, "Recognized model id %s of light ID %d as gamut B", QSTRING_CSTR(_modelId), id );
_colorSpace.red = {0.675, 0.322};
_colorSpace.green = {0.409, 0.518};
_colorSpace.blue = {0.167, 0.04};
@@ -578,7 +750,7 @@ PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject value
}
else if (GAMUT_C_MODEL_IDS.find(_modelId) != GAMUT_C_MODEL_IDS.end())
{
- Debug(_log, "Recognized model id %s of light ID %d as gamut C", QSTRING_CSTR(_modelId), id);
+ Debug(_log, "Recognized model id %s of light ID %d as gamut C", QSTRING_CSTR(_modelId), id );
_colorSpace.red = {0.6915, 0.3083};
_colorSpace.green = {0.17, 0.7};
_colorSpace.blue = {0.1532, 0.0475};
@@ -586,7 +758,7 @@ PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject value
}
else
{
- Warning(_log, "Did not recognize model id %s of light ID %d", QSTRING_CSTR(_modelId), id);
+ Warning(_log, "Did not recognize model id %s of light ID %d", QSTRING_CSTR(_modelId), id );
_colorSpace.red = {1.0, 0.0};
_colorSpace.green = {0.0, 1.0};
_colorSpace.blue = {0.0, 0.0};
@@ -596,11 +768,12 @@ PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject value
saveOriginalState(values);
_lightname = values["name"].toString().trimmed().replace("\"", "");
- Info(_log,"Light ID %d (\"%s\", LED index \"%d\") created", id, QSTRING_CSTR(_lightname), ledidx);
+ Info(_log, "Light ID %d (\"%s\", LED index \"%d\") created", id, QSTRING_CSTR(_lightname), ledidx );
}
PhilipsHueLight::~PhilipsHueLight()
{
+ DebugIf(verbose, _log, "Light ID %d (\"%s\", LED index \"%d\") deconstructed", _id, QSTRING_CSTR(_lightname), _ledidx );
}
unsigned int PhilipsHueLight::getId() const
@@ -608,7 +781,7 @@ unsigned int PhilipsHueLight::getId() const
return _id;
}
-QString PhilipsHueLight::getOriginalState()
+QString PhilipsHueLight::getOriginalState() const
{
return _originalState;
}
@@ -618,7 +791,7 @@ void PhilipsHueLight::saveOriginalState(const QJsonObject& values)
// Get state object values which are subject to change.
if (!values[API_STATE].toObject().contains("on"))
{
- Error(_log, "Got invalid state object from light ID %d", _id);
+ Error(_log, "Got invalid state object from light ID %d", _id );
}
QJsonObject lState = values[API_STATE].toObject();
_originalStateJSON = lState;
@@ -683,10 +856,26 @@ CiColorTriangle PhilipsHueLight::getColorSpace() const
LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
: LedDevicePhilipsHueBridge(deviceConfig)
- , _switchOffOnBlack (false)
+ , _switchOffOnBlack(false)
, _brightnessFactor(1.0)
- , _transitionTime (1)
- , _isRestoreOrigState (true)
+ , _transitionTime(1)
+ , _isRestoreOrigState(true)
+ , _lightStatesRestored(false)
+ , _isInitLeds(false)
+ , _lightsCount(0)
+ , _groupId(0)
+ , _brightnessMin(0.0)
+ , _brightnessMax(1.0)
+ , _allLightsBlack(false)
+ , _blackLightsTimer(nullptr)
+ , _blackLightsTimeout(15000)
+ , _brightnessThreshold(0.0)
+ , _handshake_timeout_min(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN)
+ , _handshake_timeout_max(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX)
+ , _ssl_read_timeout(STREAM_SSL_READ_TIMEOUT)
+ , _stopConnection(false)
+ , start_retry_left(3)
+ , stop_retry_left(3)
{
_devConfig = deviceConfig;
_deviceReady = false;
@@ -699,83 +888,125 @@ LedDevice* LedDevicePhilipsHue::construct(const QJsonObject &deviceConfig)
LedDevicePhilipsHue::~LedDevicePhilipsHue()
{
+ if ( _blackLightsTimer != nullptr )
+ {
+ _blackLightsTimer->deleteLater();
+ }
}
bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
{
+ verbose = deviceConfig[CONFIG_VERBOSE].toBool(false);
+
bool isInitOK = LedDevicePhilipsHueBridge::init(deviceConfig);
if ( isInitOK )
{
// Initiatiale LedDevice configuration and execution environment
- _switchOffOnBlack = _devConfig[CONFIG_ON_OFF_BLACK].toBool(true);
- _brightnessFactor = _devConfig[CONFIG_BRIGHTNESSFACTOR].toDouble(1.0);
- _transitionTime = _devConfig[CONFIG_TRANSITIONTIME].toInt(1);
- _isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(true);
- QJsonArray lArray = _devConfig[CONFIG_LIGHTIDS].toArray();
+ _switchOffOnBlack = _devConfig[CONFIG_ON_OFF_BLACK].toBool(true);
+ _blackLightsTimeout = _devConfig[CONFIG_BLACK_LIGHTS_TIMEOUT].toInt(15000);
+ _brightnessFactor = _devConfig[CONFIG_BRIGHTNESSFACTOR].toDouble(1.0);
+ _transitionTime = _devConfig[CONFIG_TRANSITIONTIME].toInt(1);
+ _isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(true);
+ _groupId = _devConfig[CONFIG_GROUPID].toInt(0);
+ _brightnessMin = _devConfig[CONFIG_BRIGHTNESS_MIN].toDouble(0.0);
+ _brightnessMax = _devConfig[CONFIG_BRIGHTNESS_MAX].toDouble(1.0);
+ _brightnessThreshold = _devConfig[CONFIG_BRIGHTNESS_THRESHOLD].toDouble(0.0);
+ _handshake_timeout_min = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN);
+ _handshake_timeout_max = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX);
+ _ssl_read_timeout = _devConfig[CONFIG_SSL_READ_TIMEOUT].toInt(STREAM_SSL_READ_TIMEOUT);
- _lightIds.clear();
- if(!lArray.empty())
+ if( _brightnessMin < 0.0 ) _brightnessMin = 0.0;
+ if( _brightnessMax > 1.0 ) _brightnessMax = 1.0;
+ if( _brightnessThreshold < 0.0 ) _brightnessThreshold = 0.0;
+ if( _brightnessThreshold > 1.0 ) _brightnessThreshold = 1.0;
+
+ if( _handshake_timeout_min <= 0 ) _handshake_timeout_min = 1;
+
+ log( "Off on Black", "%d", _switchOffOnBlack );
+ log( "Brightness Factor", "%f", _brightnessFactor );
+ log( "Transition Time", "%d", _transitionTime );
+ log( "Restore Original State", "%d", _isRestoreOrigState );
+ log( "Use Hue Entertainment API", "%d", _useHueEntertainmentAPI );
+
+ if( _useHueEntertainmentAPI )
{
- for(const auto i : lArray)
+ log( "Entertainment API Group-ID", "%d", _groupId );
+ log( "Signal Timeout on Black", "%dms", _blackLightsTimeout );
+ log( "Brightness Min", "%f", _brightnessMin );
+ log( "Brightness Max", "%f", _brightnessMax );
+ log( "Brightness Threshold", "%f", _brightnessThreshold );
+
+ if( _groupId == 0 )
{
- _lightIds.push_back(i.toInt());
+ log( "Group-ID is invalid", "%d", _groupId );
+ _useHueEntertainmentAPI = false;
}
}
-
- uint configuredLightsCount = _lightIds.size();
- Debug(_log, "Off on Black : %d", _switchOffOnBlack );
- Debug(_log, "Brightness Factor : %f", _brightnessFactor );
- Debug(_log, "Transition Time : %d", _transitionTime );
- Debug(_log, "Light IDs defined : %d", configuredLightsCount );
-
- if ( configuredLightsCount == 0)
- {
- setInError("No light-IDs configured");
- isInitOK = false;
- }
- }
- return isInitOK;
-}
-
-bool LedDevicePhilipsHue::initLeds()
-{
- bool isInitOK = false;
-
- if ( !isInError() )
- {
- updateLights( getLightMap() );
- // adapt latchTime to count of user lightIds (bridge 10Hz max overall)
- setLatchTime( static_cast( 100 * getLightsCount() ) );
- isInitOK = true;
}
return isInitOK;
}
-void LedDevicePhilipsHue::updateLights(QMap map)
+bool LedDevicePhilipsHue::setLights()
{
- if(!_lightIds.empty())
- {
- // search user lightid inside map and create light if found
- _lights.clear();
+ bool isInitOK = true;
- unsigned int ledidx = 0;
- _lights.reserve(_lightIds.size());
- for(const auto id : _lightIds)
- {
- if (map.contains(id))
- {
- _lights.emplace_back(_log, id, map.value(id), ledidx);
- }
- else
- {
- Warning(_log,"Configured light-ID %d is not available at this bridge", id);
- }
- ledidx++;
- }
- setLightsCount ( _lights.size() );
+ _lightIds.clear();
+
+ QJsonArray lArray;
+
+ if( _useHueEntertainmentAPI && _groupId > 0 )
+ {
+ lArray = getGroupLights( _groupId );
}
+
+ if( lArray.empty() )
+ {
+ if( _useHueEntertainmentAPI )
+ {
+ _useHueEntertainmentAPI = false;
+ Debug(_log, "Group-ID [%u] is not usable - Entertainment API usage was disabled!", _groupId );
+ }
+ lArray = _devConfig[ CONFIG_LIGHTIDS ].toArray();
+ }
+
+ QString lightIDStr;
+
+ if( !lArray.empty() )
+ {
+ for(const auto id : lArray)
+ {
+ unsigned int lightId = id.toString().toUInt();
+ if( lightId > 0 )
+ {
+ if(std::find(_lightIds.begin(), _lightIds.end(), lightId) == _lightIds.end())
+ {
+ _lightIds.emplace_back(lightId);
+ if(!lightIDStr.isEmpty()) lightIDStr.append(", ");
+ lightIDStr.append(QString::number(lightId));
+ }
+ }
+ }
+ std::sort( _lightIds.begin(), _lightIds.end() );
+ }
+
+ unsigned int configuredLightsCount = static_cast(_lightIds.size());
+
+ log( "Light-IDs configured", "%d", configuredLightsCount );
+
+ if ( configuredLightsCount == 0 )
+ {
+ this->setInError( "No light-IDs configured" );
+ isInitOK = false;
+ }
+ else
+ {
+ log( "Light-IDs", "%s", QSTRING_CSTR( lightIDStr ) );
+ isInitOK = updateLights( getLightMap() );
+ }
+
+ return isInitOK;
}
int LedDevicePhilipsHue::open()
@@ -797,29 +1028,359 @@ int LedDevicePhilipsHue::open()
setEnable(true);
retval = 0;
}
+ else
+ {
+ Debug(_log, "Device not usable." );
+ }
}
}
return retval;
}
-void LedDevicePhilipsHue::restoreOriginalState()
+bool LedDevicePhilipsHue::initLeds()
{
+ bool isInitOK = false;
+
+ if ( !this->isInError() )
+ {
+ if( setLights() )
+ {
+ if( _useHueEntertainmentAPI )
+ {
+ _groupName = getGroupName( _groupId );
+ _devConfig["latchTime"] = 0;
+ _devConfig["host"] = _hostname;
+ _devConfig["sslport"] = API_SSL_SERVER_PORT;
+ _devConfig["servername"] = API_SSL_SERVER_NAME;
+ _devConfig["rewriteTime"] = STREAM_REWRITE_TIME;
+ _devConfig["psk"] = _devConfig[ CONFIG_CLIENTKEY ].toString();
+ _devConfig["psk_identity"] = _devConfig[ CONFIG_USERNAME ].toString();
+ _devConfig["seed_custom"] = API_SSL_SEED_CUSTOM;
+ _devConfig["retry_left"] = STREAM_CONNECTION_RETRYS;
+ _devConfig["hs_attempts"] = STREAM_SSL_HANDSHAKE_ATTEMPTS;
+ _devConfig["hs_timeout_min"] = _handshake_timeout_min;
+ _devConfig["hs_timeout_max"] = _handshake_timeout_max;
+ _devConfig["read_timeout"] = _ssl_read_timeout;
+
+ isInitOK = ProviderUdpSSL::init( _devConfig );
+
+ if( isInitOK )
+ {
+ if ( _blackLightsTimer == nullptr )
+ {
+ _blackLightsTimer = new QTimer(this);
+ connect( _blackLightsTimer, &QTimer::timeout, this, &LedDevicePhilipsHue::noSignalTimeout );
+ }
+ }
+ }
+ else
+ {
+ // adapt latchTime to count of user lightIds (bridge 10Hz max overall)
+ setLatchTime( static_cast( 100 * getLightsCount() ) );
+ isInitOK = true;
+ }
+ _isInitLeds = true;
+ }
+ else
+ {
+ isInitOK = false;
+ }
+ }
+
+ return isInitOK;
+}
+
+bool LedDevicePhilipsHue::updateLights(QMap map)
+{
+ bool isInitOK = true;
+
+ // search user lightid inside map and create light if found
+ _lights.clear();
+
if(!_lightIds.empty())
{
- for (PhilipsHueLight& light : _lights)
+ unsigned int ledidx = 0;
+ _lights.reserve(_lightIds.size());
+ for(const auto id : _lightIds)
{
- setLightState(light.getId(),light.getOriginalState());
+ if (map.contains(id))
+ {
+ _lights.emplace_back(_log, id, map.value(id), ledidx);
+ }
+ else
+ {
+ Warning(_log, "Configured light-ID %d is not available at this bridge", id );
+ }
+ ledidx++;
+ }
+ }
+
+ unsigned int lightsCount = static_cast(_lights.size());
+
+ setLightsCount( lightsCount );
+
+ if( lightsCount == 0 )
+ {
+ Debug(_log, "No usable lights found!" );
+ isInitOK = false;
+ }
+
+ return isInitOK;
+}
+
+bool LedDevicePhilipsHue::initStream()
+{
+ bool isInitOK = false;
+
+ start_retry_left = 3;
+
+ bool streamState = getStreamGroupState();
+
+ if ( !this->isInError() )
+ {
+ // stream is already active
+ if( streamState )
+ {
+ // if same owner stop stream
+ if(isStreamOwner(_streamOwner))
+ {
+ Debug(_log, "Group: \"%s\" [%u] is in use, try to stop stream", QSTRING_CSTR(_groupName), _groupId );
+
+ if( stopStream() )
+ {
+ Debug(_log, "Stream successful stopped");
+ //Restore Philips Hue devices state
+ restoreOriginalState();
+ isInitOK = startStream();
+ }
+ else
+ {
+ Error(_log, "Group: \"%s\" [%u] couldn't stop by user: \"%s\" - Entertainment API not usable", QSTRING_CSTR( _groupName ), _groupId, QSTRING_CSTR( _streamOwner ) );
+ }
+ }
+ else
+ {
+ Error(_log, "Group: \"%s\" [%u] is in use and owned by other user: \"%s\" - Entertainment API not usable", QSTRING_CSTR(_groupName), _groupId, QSTRING_CSTR(_streamOwner));
+ }
+ }
+ else
+ {
+ isInitOK = startStream();
+ }
+ }
+
+ if( isInitOK )
+ {
+ // open UDP SSL Connection
+ isInitOK = ProviderUdpSSL::initNetwork();
+
+ if( isInitOK )
+ {
+ Info(_log, "Philips Hue Entertaiment API successful connected! Start Streaming." );
+ _allLightsBlack = true;
+ noSignalDetection();
+ }
+ else
+ {
+ Error(_log, "Philips Hue Entertaiment API not connected!" );
+ }
+ }
+ else
+ {
+ Error(_log, "Philips Hue Entertaiment API could not initialisized!" );
+ }
+
+ return isInitOK;
+}
+
+bool LedDevicePhilipsHue::startStream()
+{
+ Debug(_log, "Start entertainment stream");
+
+ if ( setStreamGroupState( true ) )
+ {
+ start_retry_left = 3;
+ return true;
+ }
+ else
+ {
+ if ( !this->isInError() )
+ {
+ QThread::msleep(500);
+ bool streamState = getStreamGroupState();
+
+ if ( !this->isInError() )
+ {
+ // stream is not active
+ if( !streamState )
+ {
+ return ( start_retry_left-- > 0 ) ? startStream() : false;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LedDevicePhilipsHue::stopStream()
+{
+ ProviderUdpSSL::closeSSLConnection();
+
+ if ( setStreamGroupState( false ) )
+ {
+ stop_retry_left = 3;
+ return true;
+ }
+ else
+ {
+ if ( !this->isInError() )
+ {
+ QThread::msleep(500);
+ bool streamState = getStreamGroupState();
+
+ if ( !this->isInError() )
+ {
+ // stream is still active
+ if( streamState )
+ {
+ return (stop_retry_left-- > 0) ? stopStream() : false;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool LedDevicePhilipsHue::getStreamGroupState()
+{
+ QJsonDocument doc = getGroupState( _groupId );
+
+ if ( !this->isInError() )
+ {
+ QJsonObject obj = doc.object()[ API_STREAM ].toObject();
+
+ if( obj.isEmpty() )
+ {
+ this->setInError( "no Streaming Infos in Group found" );
+ }
+ else
+ {
+ _streamOwner = obj.value( API_STREAM_OWNER ).toString();
+ bool streamState = obj.value( API_STREAM_ACTIVE ).toBool();
+ return streamState;
+ }
+ }
+
+ return false;
+}
+
+bool LedDevicePhilipsHue::setStreamGroupState(bool state)
+{
+ QString active = state ? API_STREAM_ACTIVE_VALUE_TRUE : API_STREAM_ACTIVE_VALUE_FALSE;
+
+ QJsonDocument doc = setGroupState( _groupId, state );
+
+ QVariant rsp = doc.toVariant();
+ QVariantMap map = rsp.toList().first().toMap();
+
+ if ( !map.contains( API_SUCCESS ) )
+ {
+ this->setInError( QString("set stream to %1: Neither error nor success contained in Bridge response...").arg( active ) );
+ }
+ else
+ {
+ QString valueName = QString( API_STREAM_RESPONSE_FORMAT ).arg( API_GROUPS ).arg( _groupId ).arg( API_STREAM ).arg( API_STREAM_ACTIVE );
+ if(!map.value( API_SUCCESS ).toMap().value( valueName ).isValid())
+ {
+ this->setInError( QString("set stream to %1: Bridge response is not Valid").arg( active ) );
+ }
+ else
+ {
+ bool groupStreamState = map.value( API_SUCCESS ).toMap().value( valueName ).toBool();
+ return ( groupStreamState == state );
+ }
+ }
+
+ return false;
+}
+
+QByteArray LedDevicePhilipsHue::prepareStreamData()
+{
+ static const uint8_t HEADER[] =
+ {
+ 'H', 'u', 'e', 'S', 't', 'r', 'e', 'a', 'm', //protocol
+ 0x01, 0x00, //version 1.0
+ 0x01, //sequence number 1
+ 0x00, 0x00, //Reserved write 0’s
+ 0x01, //xy Brightness
+ 0x00, // Reserved, write 0’s
+ };
+
+ static const uint8_t PAYLOAD_PER_LIGHT[] =
+ {
+ 0x01, 0x00, 0x06, //light ID
+ //color: 16 bpc
+ 0xff, 0xff,
+ 0xff, 0xff,
+ 0xff, 0xff,
+ /*
+ (message.R >> 8) & 0xff, message.R & 0xff,
+ (message.G >> 8) & 0xff, message.G & 0xff,
+ (message.B >> 8) & 0xff, message.B & 0xff
+ */
+ };
+
+ QByteArray msg;
+ msg.reserve(static_cast(sizeof(HEADER) + sizeof(PAYLOAD_PER_LIGHT) * _lights.size()));
+ msg.append((char*)HEADER, sizeof(HEADER));
+
+ for (PhilipsHueLight& light : _lights)
+ {
+ CiColor lightC = light.getColor();
+ quint64 R = lightC.x * 0xffff;
+ quint64 G = lightC.y * 0xffff;
+ quint64 B = lightC.bri * 0xffff;
+ unsigned int id = light.getId();
+ const uint8_t payload[] = {
+ 0x00, 0x00, static_cast(id),
+ static_cast((R >> 8) & 0xff), static_cast(R & 0xff),
+ static_cast((G >> 8) & 0xff), static_cast(G & 0xff),
+ static_cast((B >> 8) & 0xff), static_cast(B & 0xff)
+ };
+ msg.append((char*)payload, sizeof(payload));
+ }
+
+ return msg;
+}
+
+void LedDevicePhilipsHue::restoreOriginalState()
+{
+ if ( _isRestoreOrigState && !_lightStatesRestored )
+ {
+ _lightStatesRestored = true;
+
+ if( !_lightIds.empty() )
+ {
+ for ( PhilipsHueLight& light : _lights )
+ {
+ setLightState( light.getId(),light.getOriginalState() );
+ }
}
}
}
void LedDevicePhilipsHue::close()
{
+ _isInitLeds = false;
+ this->stopBlackTimeoutTimer();
+
LedDevicePhilipsHueBridge::close();
- if ( _deviceReady)
+ if ( _deviceReady )
{
- if ( _isRestoreOrigState )
+ if ( !_useHueEntertainmentAPI )
{
//Restore Philips Hue devices state
restoreOriginalState();
@@ -830,98 +1391,177 @@ void LedDevicePhilipsHue::close()
int LedDevicePhilipsHue::write(const std::vector & ledValues)
{
// lights will be empty sometimes
- if(_lights.empty()) return -1;
+ if( _lights.empty() ) return -1;
// more lights then leds, stop always
- if(ledValues.size() < getLightsCount() )
+ if( ledValues.size() < getLightsCount() )
{
- Error(_log,"More light-IDs configured than leds, each light-ID requires one led!");
+ Error(_log, "More light-IDs configured than leds, each light-ID requires one led!" );
return -1;
}
- writeSingleLights (ledValues);
+ writeSingleLights( ledValues );
+
+ if( _useHueEntertainmentAPI && !noSignalDetection() && _isInitLeds ) writeStream();
return 0;
}
+void LedDevicePhilipsHue::noSignalTimeout()
+{
+ Debug(_log, "No Signal (timeout: %sms), only black color detected - stop stream for \"%s\" [%u]", QSTRING_CSTR( QString::number( _blackLightsTimer->remainingTime() ) ), QSTRING_CSTR(_groupName), _groupId );
+ _stopConnection = true;
+ switchOff();
+}
+
+void LedDevicePhilipsHue::stopBlackTimeoutTimer()
+{
+ if ( _blackLightsTimer != nullptr && _blackLightsTimer->isActive() )
+ {
+ _blackLightsTimer->stop();
+ }
+}
+
+bool LedDevicePhilipsHue::noSignalDetection()
+{
+ if( _allLightsBlack )
+ {
+ if( !_stopConnection && _isInitLeds )
+ {
+ if ( !_blackLightsTimer->isActive() )
+ {
+ DebugIf( verbose, _log, "No Signal detected - timeout timer started" );
+ _blackLightsTimer->start( ( _blackLightsTimeout + 500 ) );
+ }
+ }
+ }
+ else
+ {
+ if ( _blackLightsTimer->isActive() )
+ {
+ DebugIf( verbose, _log, "Signal detected - timeout timer stopped" );
+ this->stopBlackTimeoutTimer();
+ }
+
+ if( _stopConnection )
+ {
+ _stopConnection = false;
+ Debug(_log, "Signal detected - restart stream for \"%s\" [%u]", QSTRING_CSTR(_groupName), _groupId );
+ switchOn();
+ }
+ }
+ return _stopConnection;
+}
+
int LedDevicePhilipsHue::writeSingleLights(const std::vector& ledValues)
{
// Iterate through lights and set colors.
unsigned int idx = 0;
- for (PhilipsHueLight& light : _lights)
+ unsigned int blackCounter = 0;
+ for ( PhilipsHueLight& light : _lights )
{
// Get color.
ColorRgb color = ledValues.at(idx);
// Scale colors from [0, 255] to [0, 1] and convert to xy space.
CiColor xy = CiColor::rgbToCiColor(color.red / 255.0, color.green / 255.0, color.blue / 255.0, light.getColorSpace());
- if (_switchOffOnBlack && xy.bri == 0.0)
+ if( _useHueEntertainmentAPI )
{
- this->setOnOffState(light, false);
+ this->setColor(light, xy);
+ if( xy.bri >= 0.0 && xy.bri <= _brightnessThreshold )
+ {
+ blackCounter++;
+ }
}
else
{
- // Write color if color has been changed.
- this->setState(light, true, xy, _brightnessFactor,_transitionTime);
+ if ( _switchOffOnBlack && xy.bri == 0.0 )
+ {
+ this->setOnOffState( light, false );
+ }
+ else
+ {
+ // Write color if color has been changed.
+ this->setState( light, true, xy );
+ }
}
idx++;
}
+
+ if( _useHueEntertainmentAPI )
+ {
+ _allLightsBlack = ( blackCounter == _lightsCount );
+ }
+
return 0;
}
+void LedDevicePhilipsHue::writeStream()
+{
+ QByteArray streamData = prepareStreamData();
+ writeBytes( streamData.size(), reinterpret_cast( streamData.data() ) );
+}
+
void LedDevicePhilipsHue::setOnOffState(PhilipsHueLight& light, bool on)
{
if (light.getOnOffState() != on)
{
light.setOnOffState( on );
QString state = on ? API_STATE_VALUE_TRUE : API_STATE_VALUE_FALSE;
- setLightState( light.getId(), QString("{\"%1\": %2 }").arg(API_STATE_ON, state) );
+ setLightState( light.getId(), QString("{\"%1\": %2 }").arg( API_STATE_ON ).arg( state ) );
}
}
-void LedDevicePhilipsHue::setTransitionTime(PhilipsHueLight& light, unsigned int transitionTime)
+void LedDevicePhilipsHue::setTransitionTime(PhilipsHueLight& light)
{
- if (light.getTransitionTime() != transitionTime)
+ if (light.getTransitionTime() != _transitionTime)
{
- light.setTransitionTime( transitionTime );
- setLightState( light.getId(), QString("{\"%1\": %2 }").arg(API_TRANSITIONTIME).arg( transitionTime ) );
+ light.setTransitionTime( _transitionTime );
+ setLightState( light.getId(), QString("{\"%1\": %2 }").arg( API_TRANSITIONTIME ).arg( _transitionTime ) );
}
}
-void LedDevicePhilipsHue::setColor(PhilipsHueLight& light, const CiColor& color, double brightnessFactor)
+void LedDevicePhilipsHue::setColor(PhilipsHueLight& light, CiColor& color)
{
- const int bri = qRound(qMin(254.0, brightnessFactor * qMax(1.0, color.bri * 254.0)));
- if (light.getColor() != color)
+ if ( light.getColor() != color )
{
- light.setColor( color) ;
- QString stateCmd = QString("\"%1\":[%2,%3],\"%4\":%5").arg(API_XY_COORDINATES).arg(color.x, 0, 'd', 4).arg(color.y, 0, 'd', 4).arg (API_BRIGHTNESS).arg(bri);
- setLightState( light.getId(), stateCmd );
+ if( !_useHueEntertainmentAPI )
+ {
+ const int bri = qRound(qMin(254.0, _brightnessFactor * qMax(1.0, color.bri * 254.0)));
+ QString stateCmd = QString("\"%1\":[%2,%3],\"%4\":%5").arg( API_XY_COORDINATES ).arg( color.x, 0, 'd', 4 ).arg( color.y, 0, 'd', 4 ).arg( API_BRIGHTNESS ).arg( bri );
+ setLightState( light.getId(), stateCmd );
+ }
+ else
+ {
+ color.bri = ( qMin( _brightnessMax, _brightnessFactor * qMax( _brightnessMin, color.bri ) ) );
+ //if(color.x == 0.0 && color.y == 0.0) color = colorBlack;
+ }
+ light.setColor( color );
}
}
-void LedDevicePhilipsHue::setState(PhilipsHueLight& light, bool on, const CiColor& color, double brightnessFactor, unsigned int transitionTime)
+void LedDevicePhilipsHue::setState(PhilipsHueLight& light, bool on, const CiColor& color)
{
-
QString stateCmd;
- if (light.getOnOffState() != on)
+ if ( light.getOnOffState() != on )
{
light.setOnOffState( on );
QString state = on ? API_STATE_VALUE_TRUE : API_STATE_VALUE_FALSE;
- stateCmd += QString("\"%1\":%2,").arg(API_STATE_ON, state);
+ stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON ).arg( state );
}
- if (light.getTransitionTime() != transitionTime)
+ if ( light.getTransitionTime() != _transitionTime )
{
- light.setTransitionTime( transitionTime );
- stateCmd += QString("\"%1\":%2,").arg(API_TRANSITIONTIME).arg( transitionTime );
+ light.setTransitionTime( _transitionTime );
+ stateCmd += QString("\"%1\":%2,").arg( API_TRANSITIONTIME ).arg( _transitionTime );
}
- const int bri = qRound(qMin(254.0, brightnessFactor * qMax(1.0, color.bri * 254.0)));
- if (light.getColor() != color)
+ const int bri = qRound( qMin( 254.0, _brightnessFactor * qMax( 1.0, color.bri * 254.0 ) ) );
+ if ( light.getColor() != color )
{
- light.setColor( color) ;
- stateCmd += QString("\"%1\":[%2,%3],\"%4\":%5").arg(API_XY_COORDINATES).arg(color.x, 0, 'd', 4).arg(color.y, 0, 'd', 4).arg (API_BRIGHTNESS).arg(bri);
+ light.setColor( color );
+ stateCmd += QString("\"%1\":[%2,%3],\"%4\":%5").arg( API_XY_COORDINATES ).arg( color.x, 0, 'd', 4 ).arg( color.y, 0, 'd', 4 ).arg( API_BRIGHTNESS ).arg( bri );
}
@@ -931,38 +1571,83 @@ void LedDevicePhilipsHue::setState(PhilipsHueLight& light, bool on, const CiColo
}
}
-
void LedDevicePhilipsHue::setLightsCount( unsigned int lightsCount )
{
_lightsCount = lightsCount;
}
+bool LedDevicePhilipsHue::reinitLeds()
+{
+ bool isInitOK = initMaps();
+
+ if( isInitOK )
+ {
+ isInitOK = initLeds();
+ }
+
+ return isInitOK;
+}
int LedDevicePhilipsHue::switchOn()
{
- if ( _deviceReady)
+ if ( _deviceReady )
{
- //Switch on Philips Hue devices physically
- for (PhilipsHueLight& light : _lights)
+ if( !_isInitLeds )
{
- setOnOffState(light,true);
+ _useHueEntertainmentAPI = _devConfig[CONFIG_USE_HUE_ENTERTAINMENT_API].toBool(false);
+ Debug(_log, "Update Bridge, Group and Light states");
+ reinitLeds();
}
+
+ bool isInitOK = false;
+
+ if( _useHueEntertainmentAPI )
+ {
+ isInitOK = initStream();
+ }
+
+ if( !isInitOK )
+ {
+ _useHueEntertainmentAPI = false;
+
+ //Switch on Philips Hue devices physically
+ for ( PhilipsHueLight& light : _lights )
+ {
+ setOnOffState( light, true );
+ }
+ }
+ _lightStatesRestored = false;
}
return 0;
}
int LedDevicePhilipsHue::switchOff()
{
+ this->stopBlackTimeoutTimer();
+
//Set all LEDs to Black
int rc = LedDevice::switchOff();
- if ( _deviceReady)
+ if ( _deviceReady )
{
- //Switch off Philips Hue devices physically
- for (PhilipsHueLight& light : _lights)
+ if( _useHueEntertainmentAPI )
{
- setOnOffState(light,false);
+ stop_retry_left = 3;
+ if( stopStream() )
+ {
+ //Restore Philips Hue devices state
+ restoreOriginalState();
+ }
}
+ else
+ {
+ //Switch off Philips Hue devices physically
+ for ( PhilipsHueLight& light : _lights )
+ {
+ setOnOffState( light, false );
+ }
+ }
+ _isInitLeds = false;
}
return rc;
}
diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
index 96332796..c6b78f5a 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
@@ -2,16 +2,38 @@
// STL includes
#include
+#include
+#include
// Qt includes
#include
-#include
+#include
+#include
+#include
+#include
// Leddevice includes
#include
+#include "ProviderUdpSSL.h"
-// Forward declaration
-struct CiColorTriangle;
+/**
+ * A XY color point in the color space of the hue system without brightness.
+ */
+struct XYColor
+{
+ /// X component.
+ double x;
+ /// Y component.
+ double y;
+};
+
+/**
+ * Color triangle to define an available color space for the hue lamps.
+ */
+struct CiColorTriangle
+{
+ XYColor red, green, blue;
+};
/**
* A color point in the color space of the hue system.
@@ -37,14 +59,14 @@ struct CiColor
///
/// @return color point
///
- static CiColor rgbToCiColor(double red, double green, double blue, CiColorTriangle colorSpace);
+ static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle &colorSpace);
///
/// @param p the color point to check
///
/// @return true if the color point is covered by the lamp color space
///
- static bool isPointInLampsReach(CiColor p, CiColorTriangle colorSpace);
+ static bool isPointInLampsReach(CiColor p, const CiColorTriangle &colorSpace);
///
/// @param p1 point one
@@ -53,7 +75,7 @@ struct CiColor
///
/// @return the cross product between p1 and p2
///
- static double crossProduct(CiColor p1, CiColor p2);
+ static double crossProduct(XYColor p1, XYColor p2);
///
/// @param a reference point one
@@ -64,7 +86,7 @@ struct CiColor
///
/// @return the closest color point of p to a and b
///
- static CiColor getClosestPointToPoint(CiColor a, CiColor b, CiColor p);
+ static XYColor getClosestPointToPoint(XYColor a, XYColor b, CiColor p);
///
/// @param p1 point one
@@ -73,20 +95,12 @@ struct CiColor
///
/// @return the distance between the two points
///
- static double getDistanceBetweenTwoPoints(CiColor p1, CiColor p2);
+ static double getDistanceBetweenTwoPoints(CiColor p1, XYColor p2);
};
bool operator==(const CiColor& p1, const CiColor& p2);
bool operator!=(const CiColor& p1, const CiColor& p2);
-/**
- * Color triangle to define an available color space for the hue lamps.
- */
-struct CiColorTriangle
-{
- CiColor red, green, blue;
-};
-
/**
* Simple class to hold the id, the latest color, the color space and the original state.
*/
@@ -120,13 +134,12 @@ public:
///
/// @param transitionTime the transition time between colors in multiples of 100 ms
///
- void setTransitionTime(unsigned int _transitionTime);
+ void setTransitionTime(unsigned int transitionTime);
///
/// @param color the color to set
///
- void setColor(const CiColor& _color);
-
+ void setColor(const CiColor& color);
unsigned int getId() const;
@@ -138,9 +151,7 @@ public:
/// @return the color space of the light determined by the model id reported by the bridge.
CiColorTriangle getColorSpace() const;
-
- QString getOriginalState();
-
+ QString getOriginalState() const;
private:
@@ -167,7 +178,7 @@ private:
CiColor _originalColor;
};
-class LedDevicePhilipsHueBridge : public LedDevice
+class LedDevicePhilipsHueBridge : public ProviderUdpSSL
{
Q_OBJECT
@@ -183,24 +194,22 @@ public:
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-
-
///
/// @param route the route of the POST request.
///
/// @param content the content of the POST request.
///
- void post(const QString& route, const QString& content);
+ QJsonDocument post(const QString& route, const QString& content);
void setLightState(unsigned int lightId = 0, QString state = "");
const QMap& getLightMap();
-// /// Set device in error state
-// ///
-// /// @param errorMsg The error message to be logged
-// ///
-// virtual void setInError( const QString& errorMsg) override;
+ const QMap& getGroupMap();
+
+ QString getGroupName(unsigned int groupId = 0);
+
+ QJsonArray getGroupLights(unsigned int groupId = 0);
public slots:
///
@@ -209,11 +218,6 @@ public slots:
virtual int open(void) override;
virtual int open( const QString& hostname, const QString& port, const QString& username );
- //signals:
- // ///
- // /// Emits with a QMap of current bridge light/value pairs
- // ///
- // void newLights(QMap map);
protected:
/// Ip address of the bridge
@@ -222,6 +226,18 @@ protected:
/// User name for the API ("newdeveloper")
QString _username;
+ bool _useHueEntertainmentAPI;
+
+ QJsonDocument getGroupState( unsigned int groupId );
+ QJsonDocument setGroupState( unsigned int groupId, bool state);
+
+ bool isStreamOwner(const QString streamOwner);
+ bool initMaps();
+
+ void log(const char* msg, const char* type, ...);
+
+ const int * getCiphersuites() override;
+
private:
///
@@ -267,6 +283,11 @@ private:
///
QJsonDocument handleReply(QNetworkReply* const &reply );
+ QJsonDocument getAllBridgeInfos();
+ void setBridgeConfig( QJsonDocument doc );
+ void setLightsMap( QJsonDocument doc );
+ void setGroupMap( QJsonDocument doc );
+
/// QNetworkAccessManager for sending requests.
QNetworkAccessManager* _networkmanager;
@@ -282,10 +303,9 @@ private:
bool _isHueEntertainmentReady;
QMap _lightsMap;
+ QMap _groupsMap;
};
-
-
/**
* Implementation for the Philips Hue system.
*
@@ -296,7 +316,6 @@ private:
*/
class LedDevicePhilipsHue: public LedDevicePhilipsHueBridge
{
-
Q_OBJECT
public:
@@ -337,10 +356,16 @@ public:
unsigned int getLightsCount() const { return _lightsCount; }
void setLightsCount( unsigned int lightsCount);
+ bool initStream();
+ bool getStreamGroupState();
+ bool setStreamGroupState(bool state);
+ bool startStream();
+ bool stopStream();
+
void setOnOffState(PhilipsHueLight& light, bool on);
- void setTransitionTime(PhilipsHueLight& light, unsigned int transitionTime);
- void setColor(PhilipsHueLight& light, const CiColor& color, double brightnessFactor);
- void setState(PhilipsHueLight& light, bool on, const CiColor& color, double brightnessFactor, unsigned int transitionTime);
+ void setTransitionTime(PhilipsHueLight& light);
+ void setColor(PhilipsHueLight& light, CiColor& color);
+ void setState(PhilipsHueLight& light, bool on, const CiColor& color);
void restoreOriginalState();
@@ -357,7 +382,9 @@ private slots:
///
/// @param map Map of lightid/value pairs of bridge
///
- void updateLights(QMap map);
+ bool updateLights(QMap map);
+
+ void noSignalTimeout();
protected:
@@ -374,6 +401,7 @@ protected:
/// @return True, if Nanoleaf device capabilities fit configuration
///
bool initLeds();
+ bool reinitLeds();
///
/// Writes the RGB-Color values to the leds.
@@ -386,8 +414,18 @@ protected:
private:
+ bool setLights();
+
int writeSingleLights(const std::vector& ledValues);
+ void writeStream();
+
+ bool noSignalDetection();
+
+ void stopBlackTimeoutTimer();
+
+ QByteArray prepareStreamData();
+
///
bool _switchOffOnBlack;
/// The brightness factor to multiply on color change.
@@ -397,6 +435,8 @@ private:
unsigned int _transitionTime;
bool _isRestoreOrigState;
+ bool _lightStatesRestored;
+ bool _isInitLeds;
/// Array of the light ids.
std::vector _lightIds;
@@ -404,6 +444,26 @@ private:
std::vector _lights;
unsigned int _lightsCount;
+ unsigned int _groupId;
+ double _brightnessMin;
+ double _brightnessMax;
+ bool _allLightsBlack;
+
+ QTimer* _blackLightsTimer;
+ unsigned int _blackLightsTimeout;
+ double _brightnessThreshold;
+
+ int _handshake_timeout_min;
+ int _handshake_timeout_max;
+ int _ssl_read_timeout;
+
+ bool _stopConnection;
+
+ QString _groupName;
+ QString _streamOwner;
+
+ int start_retry_left;
+ int stop_retry_left;
};
diff --git a/libsrc/leddevice/dev_net/ProviderUdp.cpp b/libsrc/leddevice/dev_net/ProviderUdp.cpp
index dd4b5b97..ef4d51b1 100644
--- a/libsrc/leddevice/dev_net/ProviderUdp.cpp
+++ b/libsrc/leddevice/dev_net/ProviderUdp.cpp
@@ -77,7 +77,7 @@ bool ProviderUdp::initNetwork()
{
bool isInitOK = false;
- _udpSocket =new QUdpSocket(this);
+ _udpSocket = new QUdpSocket(this);
if ( _udpSocket != nullptr)
{
diff --git a/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp b/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
new file mode 100644
index 00000000..0eab17a8
--- /dev/null
+++ b/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
@@ -0,0 +1,801 @@
+
+// STL includes
+#include
+#include
+
+// Linux includes
+#include
+#ifndef _WIN32
+ #include
+#endif
+
+// Local Hyperion includes
+#include "ProviderUdpSSL.h"
+
+ProviderUdpSSL::ProviderUdpSSL()
+ : LedDevice()
+ , client_fd()
+ , entropy()
+ , ssl()
+ , conf()
+ , ctr_drbg()
+ , timer()
+ , _transport_type("DTLS")
+ , _custom("dtls_client")
+ , _address("127.0.0.1")
+ , _defaultHost("127.0.0.1")
+ , _port(1)
+ , _ssl_port(1)
+ , _server_name()
+ , _psk()
+ , _psk_identity()
+ , _read_timeout(0)
+ , _handshake_timeout_min(400)
+ , _handshake_timeout_max(1000)
+ , _handshake_attempts(5)
+ , _retry_left(MAX_RETRY)
+ , _stopConnection(true)
+ , _debugStreamer(false)
+ , _debugLevel(0)
+{
+ _deviceReady = false;
+ _latchTime_ms = 1;
+}
+
+ProviderUdpSSL::~ProviderUdpSSL()
+{
+}
+
+bool ProviderUdpSSL::init(const QJsonObject &deviceConfig)
+{
+ bool isInitOK = LedDevice::init(deviceConfig);
+
+ _debugStreamer = deviceConfig["debugStreamer"].toBool(false);
+ _debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
+
+ //PSK Pre Shared Key
+ _psk = deviceConfig["psk"].toString();
+ _psk_identity = deviceConfig["psk_identity"].toString();
+ _port = deviceConfig["sslport"].toInt(2100);
+ _server_name = deviceConfig["servername"].toString();
+
+ if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
+ if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
+ if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
+ if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
+ if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
+ if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
+ if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
+
+ QString host = deviceConfig["host"].toString(_defaultHost);
+ QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
+
+ configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
+ configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
+
+ configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
+ configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
+ configLog( "SSL Port", "%d", _port );
+ configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
+ configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
+ configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
+ configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
+ configLog( "SSL Retry Left", "%d", _retry_left );
+ configLog( "SSL Read Timeout", "%d", _read_timeout );
+ configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
+ configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
+ configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
+
+ if ( _address.setAddress(host) )
+ {
+ Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
+ }
+ else
+ {
+ Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
+ QHostInfo info = QHostInfo::fromName(host);
+ if ( info.addresses().isEmpty() )
+ {
+ Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
+ QString errortext = QString("Invalid target address [%1]!").arg(host);
+ this->setInError( errortext );
+ isInitOK = false;
+ }
+ else
+ {
+ Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
+ _address = info.addresses().first();
+ }
+ }
+
+ int config_port = deviceConfig["sslport"].toInt(_port);
+
+ if ( config_port <= 0 || config_port > MAX_PORT_SSL )
+ {
+ QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
+ this->setInError( errortext );
+ isInitOK = false;
+ }
+ else
+ {
+ _ssl_port = config_port;
+ Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
+ }
+ return isInitOK;
+}
+
+int ProviderUdpSSL::open()
+{
+ int retval = -1;
+ QString errortext;
+ _deviceReady = false;
+
+ if ( init(_devConfig) )
+ {
+ if ( !initNetwork() )
+ {
+ this->setInError( "UDP SSL Network error!" );
+ }
+ else
+ {
+ // Everything is OK -> enable device
+ _deviceReady = true;
+ setEnable(true);
+ retval = 0;
+ }
+ }
+ return retval;
+}
+
+void ProviderUdpSSL::close()
+{
+ LedDevice::close();
+ closeSSLConnection();
+}
+
+void ProviderUdpSSL::closeSSLConnection()
+{
+ if( _deviceReady && !_stopConnection )
+ {
+ closeSSLNotify();
+ freeSSLConnection();
+ }
+}
+
+const int *ProviderUdpSSL::getCiphersuites()
+{
+ return mbedtls_ssl_list_ciphersuites();
+}
+
+void ProviderUdpSSL::configLog(const char* msg, const char* type, ...)
+{
+ if( _debugStreamer )
+ {
+ const size_t max_val_length = 1024;
+ char val[max_val_length];
+ va_list args;
+ va_start(args, type);
+ vsnprintf(val, max_val_length, type, args);
+ va_end(args);
+ std::string s = msg;
+ int max = 30;
+ s.append(max - s.length(), ' ');
+ Debug( _log, "%s: %s", s.c_str(), val );
+ }
+}
+
+void ProviderUdpSSL::sslLog(const QString &msg, const char* errorType)
+{
+ sslLog( QSTRING_CSTR( msg ), errorType );
+}
+
+void ProviderUdpSSL::sslLog(const char* msg, const char* errorType)
+{
+ if( strcmp("fatal", errorType) == 0 ) Error( _log, "%s", msg );
+
+ if( _debugStreamer )
+ {
+ if( strcmp("debug", errorType) == 0 ) Debug( _log, "%s", msg );
+ if( strcmp("warning", errorType) == 0 ) Warning( _log, "%s", msg );
+ if( strcmp("error", errorType) == 0 ) Error( _log, "%s", msg );
+ }
+}
+
+bool ProviderUdpSSL::initNetwork()
+{
+ sslLog( "init SSL Network..." );
+ QMutexLocker locker(&_hueMutex);
+ if (!initConnection()) return false;
+ sslLog( "init SSL Network...ok" );
+ _stopConnection = false;
+ return true;
+}
+
+bool ProviderUdpSSL::initConnection()
+{
+ sslLog( "init SSL Network -> initConnection" );
+
+ mbedtls_net_init(&client_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ if(!seedingRNG()) return false;
+ return setupStructure();
+}
+
+bool ProviderUdpSSL::seedingRNG()
+{
+ int ret = 0;
+
+ sslLog( "Seeding the random number generator..." );
+
+ mbedtls_entropy_init(&entropy);
+
+ sslLog( "Set mbedtls_ctr_drbg_seed..." );
+
+ const char* custom = QSTRING_CSTR( _custom );
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, reinterpret_cast(custom), strlen(custom))) != 0)
+ {
+ sslLog( QString("mbedtls_ctr_drbg_seed FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ sslLog( "Seeding the random number generator...ok" );
+
+ return true;
+}
+
+bool ProviderUdpSSL::setupStructure()
+{
+ int ret = 0;
+
+ sslLog( QString( "Setting up the %1 structure").arg( _transport_type ) );
+
+ //TLS MBEDTLS_SSL_TRANSPORT_STREAM
+ //DTLS MBEDTLS_SSL_TRANSPORT_DATAGRAM
+
+ int transport = ( _transport_type == "DTLS" ) ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM;
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, transport, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
+ {
+ sslLog( QString("mbedtls_ssl_config_defaults FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ const int * ciphersuites = getCiphersuites();
+
+ if( _debugStreamer )
+ {
+ int s = ( sizeof( ciphersuites ) ) / sizeof( int );
+
+ QString cipher_values;
+ for(int i=0; i 0) cipher_values.append(", ");
+ cipher_values.append(QString::number(ciphersuites[i]));
+ }
+
+ sslLog( ( QString("used ciphersuites value: %1").arg( cipher_values ) ) );
+ }
+
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+ //mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ //mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+
+ mbedtls_ssl_conf_ciphersuites(&conf, ciphersuites);
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+ if ( _debugLevel > 0)
+ {
+ mbedtls_ssl_conf_verify(&conf, ProviderUdpSSLVerify, NULL);
+ mbedtls_ssl_conf_dbg(&conf, ProviderUdpSSLDebug, NULL);
+ mbedtls_debug_set_threshold( _debugLevel );
+ }
+
+ if( _read_timeout > 0 ) mbedtls_ssl_conf_read_timeout(&conf, _read_timeout);
+
+ mbedtls_ssl_conf_handshake_timeout(&conf, _handshake_timeout_min, _handshake_timeout_max);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
+ {
+ sslLog( QString("mbedtls_ssl_setup FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, QSTRING_CSTR( _server_name ))) != 0)
+ {
+ sslLog( QString("mbedtls_ssl_set_hostname FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ sslLog( QString( "Setting up the %1 structure...ok").arg( _transport_type ) );
+
+ return startUPDConnection();
+}
+
+bool ProviderUdpSSL::startUPDConnection()
+{
+ sslLog( "init SSL Network -> startUPDConnection" );
+
+ int ret = 0;
+
+ mbedtls_ssl_session_reset(&ssl);
+
+ if(!setupPSK()) return false;
+
+ sslLog( QString("Connecting to udp %1:%2").arg( _address.toString() ).arg( _ssl_port ) );
+
+ if ((ret = mbedtls_net_connect( &client_fd, _address.toString().toUtf8(), std::to_string(_ssl_port).c_str(), MBEDTLS_NET_PROTO_UDP)) != 0)
+ {
+ sslLog( QString("mbedtls_net_connect FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
+
+ sslLog( "Connecting...ok" );
+
+ return startSSLHandshake();
+}
+
+bool ProviderUdpSSL::setupPSK()
+{
+ int ret;
+
+ QByteArray pskArray = _psk.toUtf8();
+ QByteArray pskRawArray = QByteArray::fromHex(pskArray);
+
+ QByteArray pskIdArray = _psk_identity.toUtf8();
+ QByteArray pskIdRawArray = pskIdArray;
+
+ if (0 != (ret = mbedtls_ssl_conf_psk( &conf, ( const unsigned char* ) pskRawArray.data(), pskRawArray.length() * sizeof(char), reinterpret_cast ( pskIdRawArray.data() ), pskIdRawArray.length() * sizeof(char) ) ) )
+ {
+ sslLog( QString("mbedtls_ssl_conf_psk FAILED %1").arg( errorMsg( ret ) ), "error" );
+ return false;
+ }
+
+ return true;
+}
+
+bool ProviderUdpSSL::startSSLHandshake()
+{
+ sslLog( "init SSL Network -> startSSLHandshake" );
+
+ int ret = 0;
+
+ sslLog( QString( "Performing the SSL/%1 handshake...").arg( _transport_type ) );
+
+ for (unsigned int attempt = 1; attempt <= _handshake_attempts; ++attempt)
+ {
+ sslLog( QString("handshake attempt %1/%2").arg( attempt ).arg( _handshake_attempts ) );
+ do
+ {
+ ret = mbedtls_ssl_handshake(&ssl);
+ }
+ while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret == 0)
+ {
+ break;
+ }
+ else
+ {
+ sslLog( QString("mbedtls_ssl_handshake attempt %1/%2 FAILED %3").arg( attempt ).arg( _handshake_attempts ).arg( errorMsg( ret ) ) );
+ }
+
+ QThread::msleep(200);
+ }
+
+ if (ret != 0)
+ {
+ sslLog( QString("mbedtls_ssl_handshake FAILED %1").arg( errorMsg( ret ) ), "error" );
+ handleReturn(ret);
+ sslLog( "UDP SSL Connection failed!", "fatal" );
+ return false;
+ }
+ else
+ {
+ if( ( mbedtls_ssl_get_verify_result( &ssl ) ) != 0 ) {
+ sslLog( "SSL certificate verification failed!", "fatal" );
+ return false;
+ }
+ }
+
+ sslLog( QString( "Performing the SSL/%1 handshake...ok").arg( _transport_type ) );
+
+ return true;
+}
+
+void ProviderUdpSSL::freeSSLConnection()
+{
+ sslLog( "SSL Connection cleanup..." );
+
+ _stopConnection = true;
+
+ try
+ {
+ mbedtls_ssl_session_reset(&ssl);
+ mbedtls_net_free(&client_fd);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+ sslLog( "SSL Connection cleanup...ok" );
+ }
+ catch (std::exception &e)
+ {
+ sslLog( QString("SSL Connection cleanup Error: %s").arg( e.what() ) );
+ }
+ catch (...)
+ {
+ sslLog( "SSL Connection cleanup Error: " );
+ }
+}
+
+void ProviderUdpSSL::writeBytes(const unsigned size, const unsigned char * data)
+{
+ if( _stopConnection ) return;
+
+ QMutexLocker locker(&_hueMutex);
+
+ int ret = 0;
+
+ do
+ {
+ ret = mbedtls_ssl_write(&ssl, data, size);
+ }
+ while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret <= 0)
+ {
+ handleReturn(ret);
+ }
+}
+
+void ProviderUdpSSL::handleReturn(int ret)
+{
+ bool closeNotify = false;
+ bool gotoExit = false;
+
+ switch (ret)
+ {
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ sslLog( errorMsg( ret ), "warning" );
+ if ( _retry_left-- > 0 ) return;
+ gotoExit = true;
+ break;
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ sslLog( "SSL Connection was closed gracefully", "warning" );
+ ret = 0;
+ closeNotify = true;
+ break;
+ default:
+ sslLog( QString("mbedtls_ssl_read returned %1").arg( errorMsg( ret ) ), "warning" );
+ gotoExit = true;
+ }
+
+ if (closeNotify)
+ {
+ closeSSLNotify();
+ gotoExit = true;
+ }
+
+ if (gotoExit)
+ {
+ sslLog( "Exit SSL connection" );
+ _stopConnection = true;
+ }
+}
+
+QString ProviderUdpSSL::errorMsg(int ret) {
+
+ QString msg;
+
+#ifdef MBEDTLS_ERROR_C
+ char error_buf[1024];
+ mbedtls_strerror(ret, error_buf, 1024);
+ msg = QString("Last error was: %1 - %2").arg( ret ).arg( error_buf );
+#else
+ switch (ret)
+ {
+#if defined(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE)
+ case MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE:
+ msg = "The requested feature is not available. - MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE -0x7080";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_INPUT_DATA)
+ case MBEDTLS_ERR_SSL_BAD_INPUT_DATA:
+ msg = "Bad input parameters to function. - MBEDTLS_ERR_SSL_BAD_INPUT_DATA -0x7100";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_INVALID_MAC)
+ case MBEDTLS_ERR_SSL_INVALID_MAC:
+ msg = "Verification of the message MAC failed. - MBEDTLS_ERR_SSL_INVALID_MAC -0x7180";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_INVALID_RECORD)
+ case MBEDTLS_ERR_SSL_INVALID_RECORD:
+ msg = "An invalid SSL record was received. - MBEDTLS_ERR_SSL_INVALID_RECORD -0x7200";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CONN_EOF)
+ case MBEDTLS_ERR_SSL_CONN_EOF:
+ msg = "The connection indicated an EOF. - MBEDTLS_ERR_SSL_CONN_EOF -0x7280";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER)
+ case MBEDTLS_ERR_SSL_UNKNOWN_CIPHER:
+ msg = "An unknown cipher was received. - MBEDTLS_ERR_SSL_UNKNOWN_CIPHER -0x7300";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN)
+ case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
+ msg = "The server has no ciphersuites in common with the client. - MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN -0x7380";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_NO_RNG)
+ case MBEDTLS_ERR_SSL_NO_RNG:
+ msg = "No RNG was provided to the SSL module. - MBEDTLS_ERR_SSL_NO_RNG -0x7400";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE)
+ case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE:
+ msg = "No client certification received from the client, but required by the authentication mode. - MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE)
+ case MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE:
+ msg = "Our own certificate(s) is/are too large to send in an SSL message. - MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED)
+ case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED:
+ msg = "The own certificate is not set, but needed by the server. - MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED -0x7580";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED)
+ case MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED:
+ msg = "The own private key or pre-shared key is not set, but needed. - MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED)
+ case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED:
+ msg = "No CA Chain is set, but required to operate. - MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED -0x7680";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE)
+ case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE:
+ msg = "An unexpected message was received from our peer. - MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE -0x7700";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)
+ case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
+ msg = "A fatal alert message was received from our peer. - MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED)
+ case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED:
+ msg = "Verification of our peer failed. - MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED -0x7800";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ msg = "The peer notified us that the connection is going to be closed. - MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO)
+ case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO:
+ msg = "Processing of the ClientHello handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO)
+ case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO:
+ msg = "Processing of the ServerHello handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE)
+ case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE:
+ msg = "Processing of the Certificate handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST)
+ case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST:
+ msg = "Processing of the CertificateRequest handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE)
+ case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE:
+ msg = "Processing of the ServerKeyExchange handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE)
+ case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE:
+ msg = "Processing of the ServerHelloDone handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE)
+ case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE:
+ msg = "Processing of the ClientKeyExchange handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP)
+ case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP:
+ msg = "Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP -0x7C80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS)
+ case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS:
+ msg = "Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS -0x7D00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY)
+ case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY:
+ msg = "Processing of the CertificateVerify handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC)
+ case MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC:
+ msg = "Processing of the ChangeCipherSpec handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_FINISHED)
+ case MBEDTLS_ERR_SSL_BAD_HS_FINISHED:
+ msg = "Processing of the Finished handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_ALLOC_FAILED)
+ case MBEDTLS_ERR_SSL_ALLOC_FAILED:
+ msg = "Memory allocation failed. - MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED)
+ case MBEDTLS_ERR_SSL_HW_ACCEL_FAILED:
+ msg = "Hardware acceleration function returned with error. - MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -0x7F80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH)
+ case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
+ msg = "Hardware acceleration function skipped / left alone data. - MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_COMPRESSION_FAILED)
+ case MBEDTLS_ERR_SSL_COMPRESSION_FAILED:
+ msg = "Processing of the compression / decompression failed. - MBEDTLS_ERR_SSL_COMPRESSION_FAILED -0x6F00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION)
+ case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
+ msg = "Handshake protocol not within min/max boundaries. - MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET)
+ case MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET:
+ msg = "Processing of the NewSessionTicket handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED)
+ case MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED:
+ msg = "Session ticket has expired. - MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED -0x6D80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH)
+ case MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH:
+ msg = "Public key type mismatch (eg, asked for RSA key exchange and presented EC key) - MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH -0x6D00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY)
+ case MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY:
+ msg = "Unknown identity received (eg, PSK identity) - MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY -0x6C80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_INTERNAL_ERROR)
+ case MBEDTLS_ERR_SSL_INTERNAL_ERROR:
+ msg = "Internal error (eg, unexpected failure in lower-level module) - MBEDTLS_ERR_SSL_INTERNAL_ERROR -0x6C00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_COUNTER_WRAPPING)
+ case MBEDTLS_ERR_SSL_COUNTER_WRAPPING:
+ msg = "A counter would wrap (eg, too many messages exchanged). - MBEDTLS_ERR_SSL_COUNTER_WRAPPING -0x6B80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO)
+ case MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO:
+ msg = "Unexpected message at ServerHello in renegotiation. - MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED)
+ case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:
+ msg = "DTLS client must retry for hello verification. - MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL)
+ case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL:
+ msg = "A buffer is too small to receive or write a message. - MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE)
+ case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
+ msg = "None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). - MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_WANT_READ)
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ msg = "No data of requested type currently available on underlying transport. - MBEDTLS_ERR_SSL_WANT_READ -0x6900";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_WANT_WRITE)
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ msg = "Connection requires a write call. - MBEDTLS_ERR_SSL_WANT_WRITE -0x6880";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_TIMEOUT)
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ msg = "The operation timed out. - MBEDTLS_ERR_SSL_TIMEOUT -0x6800";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CLIENT_RECONNECT)
+ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
+ msg = "The client initiated a reconnect from the same port. - MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD)
+ case MBEDTLS_ERR_SSL_UNEXPECTED_RECORD:
+ msg = "Record header looks valid but is not expected. - MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_NON_FATAL)
+ case MBEDTLS_ERR_SSL_NON_FATAL:
+ msg = "The alert message received indicates a non-fatal error. - MBEDTLS_ERR_SSL_NON_FATAL -0x6680";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH)
+ case MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH:
+ msg = "Couldn't set the hash for verifying CertificateVerify. - MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING)
+ case MBEDTLS_ERR_SSL_CONTINUE_PROCESSING:
+ msg = "Internal-only message signaling that further message-processing should be done. - MBEDTLS_ERR_SSL_CONTINUE_PROCESSING -0x6580";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ msg = "The asynchronous operation is not completed yet. - MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_EARLY_MESSAGE)
+ case MBEDTLS_ERR_SSL_EARLY_MESSAGE:
+ msg = "Internal-only message signaling that a message arrived early. - MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480";
+ break;
+#endif
+#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ msg = "A cryptographic operation is in progress. - MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000";
+ break;
+#endif
+ default:
+ msg.append("Last error was: ").append( QString::number(ret) );
+ }
+#endif
+ return msg;
+}
+
+void ProviderUdpSSL::closeSSLNotify()
+{
+ int ret = 0;
+
+ sslLog( "Closing SSL connection..." );
+ /* No error checking, the connection might be closed already */
+ do
+ {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ }
+ while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ sslLog( "SSL Connection successful closed" );
+}
diff --git a/libsrc/leddevice/dev_net/ProviderUdpSSL.h b/libsrc/leddevice/dev_net/ProviderUdpSSL.h
new file mode 100644
index 00000000..da0a5a7f
--- /dev/null
+++ b/libsrc/leddevice/dev_net/ProviderUdpSSL.h
@@ -0,0 +1,210 @@
+#pragma once
+
+#include
+#include
+
+// Qt includes
+#include
+#include
+#include
+#include
+
+//----------- mbedtls
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include
+#else
+#include
+#include
+#define mbedtls_time time
+#define mbedtls_time_t time_t
+#define mbedtls_printf printf
+#define mbedtls_fprintf fprintf
+#define mbedtls_snprintf snprintf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#define mbedtls_exit exit
+#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
+#endif
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define READ_TIMEOUT_MS 1000
+#define MAX_RETRY 5
+
+//----------- END mbedtls
+
+const ushort MAX_PORT_SSL = 65535;
+
+class ProviderUdpSSL : public LedDevice
+{
+ Q_OBJECT
+
+public:
+ ///
+ /// Constructs specific LedDevice
+ ///
+ ProviderUdpSSL();
+
+ ///
+ /// Destructor of the LedDevice; closes the output device if it is open
+ ///
+ virtual ~ProviderUdpSSL() override;
+
+ ///
+ /// Sets configuration
+ ///
+ /// @param deviceConfig the json device config
+ /// @return true if success
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+public slots:
+ ///
+ /// Closes the output device.
+ /// Includes switching-off the device and stopping refreshes
+ ///
+ virtual void close() override;
+
+protected:
+
+ ///
+ /// Initialise device's network details
+ ///
+ /// @return True if success
+ ///
+ bool initNetwork();
+
+ ///
+ /// Opens and configures the output device
+ ///
+ /// @return Zero on succes else negative
+ ///
+ int open() override;
+
+ ///
+ /// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
+ /// values are latched.
+ ///
+ /// @param[in] size The length of the data
+ /// @param[in] data The data
+ ///
+ void writeBytes(const unsigned size, const uint8_t *data);
+
+ ///
+ /// get ciphersuites list from mbedtls_ssl_list_ciphersuites
+ ///
+ /// @return const int * array
+ ///
+ virtual const int * getCiphersuites();
+
+ void sslLog(const QString &msg, const char* errorType = "debug");
+ void sslLog(const char* msg, const char* errorType = "debug");
+ void configLog(const char* msg, const char* type, ...);
+
+ /**
+ * Debug callback for mbed TLS
+ * Just prints on the USB serial port
+ */
+ static void ProviderUdpSSLDebug(void *ctx, int level, const char *file, int line, const char *str)
+ {
+ const char *p, *basename;
+ (void) ctx;
+ /* Extract basename from file */
+ for(p = basename = file; *p != '\0'; p++)
+ {
+ if(*p == '/' || *p == '\\')
+ {
+ basename = p + 1;
+ }
+ }
+ mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
+ }
+
+ /**
+ * Certificate verification callback for mbed TLS
+ * Here we only use it to display information on each cert in the chain
+ */
+ static int ProviderUdpSSLVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
+ {
+ const uint32_t buf_size = 1024;
+ char *buf = new char[buf_size];
+ (void) data;
+
+ mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
+ mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
+ mbedtls_printf("%s", buf);
+
+ if (*flags == 0)
+ mbedtls_printf("No verification issue for this certificate\n");
+ else
+ {
+ mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
+ mbedtls_printf("%s\n", buf);
+ }
+
+ delete[] buf;
+ return 0;
+ }
+
+ ///
+ /// closeSSLNotify and freeSSLConnection
+ ///
+ void closeSSLConnection();
+
+private:
+
+ bool buildConnection();
+ bool initConnection();
+ bool seedingRNG();
+ bool setupStructure();
+ bool startUPDConnection();
+ bool setupPSK();
+ bool startSSLHandshake();
+ void handleReturn(int ret);
+ QString errorMsg(int ret);
+ void closeSSLNotify();
+ void freeSSLConnection();
+
+ mbedtls_net_context client_fd;
+ mbedtls_entropy_context entropy;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt cacert;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_timing_delay_context timer;
+
+ QMutex _hueMutex;
+ QString _transport_type;
+ QString _custom;
+ QHostAddress _address;
+ QString _defaultHost;
+ int _port;
+ int _ssl_port;
+ QString _server_name;
+ QString _psk;
+ QString _psk_identity;
+ uint32_t _read_timeout;
+ uint32_t _handshake_timeout_min;
+ uint32_t _handshake_timeout_max;
+ unsigned int _handshake_attempts;
+ int _retry_left;
+ bool _stopConnection;
+ bool _debugStreamer;
+ int _debugLevel;
+};
diff --git a/libsrc/leddevice/schemas/schema-philipshue.json b/libsrc/leddevice/schemas/schema-philipshue.json
index d90a85d6..b27e62a4 100644
--- a/libsrc/leddevice/schemas/schema-philipshue.json
+++ b/libsrc/leddevice/schemas/schema-philipshue.json
@@ -14,45 +14,233 @@
"default": "",
"propertyOrder" : 2
},
+ "clientkey": {
+ "type": "string",
+ "title":"edt_dev_spec_clientKey_title",
+ "default" : "",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 3
+ },
+ "useEntertainmentAPI": {
+ "type": "boolean",
+ "title":"edt_dev_spec_useEntertainmentAPI_title",
+ "default" : false,
+ "propertyOrder" : 4
+ },
"transitiontime": {
- "type": "integer",
+ "type": "number",
"title":"edt_dev_spec_transistionTime_title",
"default" : 1,
"append" : "x100ms",
- "propertyOrder" : 3
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": false
+ }
+ },
+ "propertyOrder" : 5
},
"switchOffOnBlack": {
"type": "boolean",
"title":"edt_dev_spec_switchOffOnBlack_title",
"default" : true,
- "propertyOrder" : 4
- },
- "brightnessFactor": {
- "type": "number",
- "title":"edt_dev_spec_brightnessFactor_title",
- "default" : 1.0,
- "minimum" : 0.5,
- "maximum" : 10.0,
- "propertyOrder" : 5
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": false
+ }
+ },
+ "propertyOrder" : 6
},
"restoreOriginalState": {
"type": "boolean",
"title":"edt_dev_spec_restoreOriginalState_title",
"default" : true,
- "propertyOrder" : 6
+ "propertyOrder" : 7
},
-
"lightIds": {
"type": "array",
"title":"edt_dev_spec_lightid_title",
"minItems": 1,
"uniqueItems" : true,
"items" : {
- "type" : "integer",
+ "type" : "string",
"minimum" : 0,
"title" : "edt_dev_spec_lightid_itemtitle"
},
- "propertyOrder" : 7
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": false
+ }
+ },
+ "propertyOrder" : 8
+ },
+ "groupId": {
+ "type": "number",
+ "title":"edt_dev_spec_groupId_title",
+ "default" : 0,
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 9
+ },
+ "blackLightsTimeout": {
+ "type": "number",
+ "title":"edt_dev_spec_blackLightsTimeout_title",
+ "default" : 15000,
+ "step": 500,
+ "minimum" : 10000,
+ "maximum" : 60000,
+ "access" : "advanced",
+ "append" : "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 10
+ },
+ "brightnessThreshold": {
+ "type": "number",
+ "title":"edt_dev_spec_brightnessThreshold_title",
+ "default" : 0,
+ "step": 0.005,
+ "minimum" : 0,
+ "maximum" : 1.0,
+ "access" : "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 11
+ },
+ "brightnessFactor": {
+ "type": "number",
+ "title":"edt_dev_spec_brightnessFactor_title",
+ "default" : 1.0,
+ "step": 0.25,
+ "minimum" : 0.5,
+ "maximum" : 10.0,
+ "access" : "advanced",
+ "propertyOrder" : 12
+ },
+ "brightnessMin": {
+ "type": "number",
+ "title":"edt_dev_spec_brightnessMin_title",
+ "default" : 0,
+ "step": 0.05,
+ "minimum" : 0,
+ "maximum" : 1.0,
+ "access" : "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 13
+ },
+ "brightnessMax": {
+ "type": "number",
+ "title":"edt_dev_spec_brightnessMax_title",
+ "default" : 1.0,
+ "step": 0.05,
+ "minimum" : 0,
+ "maximum" : 1.0,
+ "access" : "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 14
+ },
+ "sslReadTimeout": {
+ "type": "number",
+ "title":"edt_dev_spec_sslReadTimeout_title",
+ "default" : 0,
+ "step": 100,
+ "minimum" : 0,
+ "maximum" : 30000,
+ "access" : "expert",
+ "append" : "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 15
+ },
+ "sslHSTimeoutMin": {
+ "type": "number",
+ "title":"edt_dev_spec_sslHSTimeoutMin_title",
+ "default" : 400,
+ "step": 100,
+ "minimum" : 0,
+ "maximum" : 30000,
+ "access" : "expert",
+ "append" : "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 16
+ },
+ "sslHSTimeoutMax": {
+ "type": "number",
+ "title":"edt_dev_spec_sslHSTimeoutMax_title",
+ "default" : 1000,
+ "step": 100,
+ "minimum" : 0,
+ "maximum" : 30000,
+ "access" : "expert",
+ "append" : "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 17
+ },
+ "verbose": {
+ "type": "boolean",
+ "title":"edt_dev_spec_verbose_title",
+ "default" : false,
+ "access" : "expert",
+ "propertyOrder" : 18
+ },
+ "debugStreamer": {
+ "type": "boolean",
+ "title":"edt_dev_spec_debugStreamer_title",
+ "default" : false,
+ "access" : "expert",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder" : 19
+ },
+ "debugLevel": {
+ "type": "string",
+ "title":"edt_dev_spec_debugLevel_title",
+ "enum" : ["0", "1", "2", "3", "4"],
+ "default" : "0",
+ "options" : {
+ "enum_titles" : ["edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_error", "edt_conf_enum_dl_statechange", "edt_conf_enum_dl_informational", "edt_conf_enum_dl_verbose"],
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "minimum" : 0,
+ "maximum" : 4,
+ "access" : "expert",
+ "propertyOrder" : 20
}
},
"additionalProperties": true
diff --git a/libsrc/ssdp/SSDPHandler.cpp b/libsrc/ssdp/SSDPHandler.cpp
index 1c5fa082..04944a4f 100644
--- a/libsrc/ssdp/SSDPHandler.cpp
+++ b/libsrc/ssdp/SSDPHandler.cpp
@@ -24,7 +24,7 @@ SSDPHandler::SSDPHandler(WebServer* webserver, const quint16& flatBufPort, const
SSDPHandler::~SSDPHandler()
{
- sendAnnounceList(false);
+ stopServer();
}
void SSDPHandler::initServer()
@@ -60,6 +60,12 @@ void SSDPHandler::initServer()
}
}
+void SSDPHandler::stopServer()
+{
+ sendAnnounceList(false);
+ SSDPServer::stop();
+}
+
void SSDPHandler::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
{
if(type == settings::FLATBUFSERVER)
diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp
index dd84c9e4..49b7fc38 100644
--- a/src/hyperiond/hyperiond.cpp
+++ b/src/hyperiond/hyperiond.cpp
@@ -112,6 +112,9 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, const bo
//connect(_hyperion,SIGNAL(closing()),this,SLOT(freeObjects())); // TODO for app restart, refactor required
+ //Cleaning up Hyperion before quit
+ connect(parent, SIGNAL(aboutToQuit()), this, SLOT(freeObjects()));
+
// pipe settings changes and component state changes from HyperionIManager to Daemon
connect(_instanceManager, &HyperionIManager::settingsChanged, this, &HyperionDaemon::settingsChanged);
connect(_instanceManager, &HyperionIManager::compStateChangeRequest, this, &HyperionDaemon::compStateChangeRequest);
@@ -141,7 +144,6 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, const bo
HyperionDaemon::~HyperionDaemon()
{
- freeObjects();
delete _settingsManager;
delete _pyInit;
}
@@ -162,6 +164,8 @@ const QJsonDocument HyperionDaemon::getSetting(const settings::type &type)
void HyperionDaemon::freeObjects()
{
+ Debug(_log, "Cleaning up Hyperion before quit.");
+
// destroy network first as a client might want to access hyperion
delete _jsonServer;
_flatBufferServer->thread()->quit();
diff --git a/src/hyperiond/hyperiond.h b/src/hyperiond/hyperiond.h
index 4f55bf4b..a091933e 100644
--- a/src/hyperiond/hyperiond.h
+++ b/src/hyperiond/hyperiond.h
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
#include