$(document).ready(function() { var lights, groups, scenes, $roomsList = $('#rooms-list'), $lightsList = $('#lights-list'), $scenesList = $('#scenes-list'); var onEvent = function(event) { switch (event.args.type) { case 'platypush.message.event.light.LightStatusChangeEvent': var $lightsList = $('#lights-list'); var $light = $lightsList.find('.light-item').filter( (i, light) => $(light).data('id') == event.args.light_id ); var $roomLights = $light.parent('.room-lights-item').find('.light-item').filter( (i, light) => $(light).data('type') == 'light' ); var $allLightsItem = $light.parent('.room-lights-item').find('.light-item').filter( (i, light) => $(light).data('type') == 'room' ); if ('on' in event.args) { $light.find('.light-ctrl-switch').prop('checked', event.args.on); if ($roomLights.find('.light-ctrl-switch:checked').length > 0) { $allLightsItem.find('.light-ctrl-switch').prop('checked', true); } else { $allLightsItem.find('.light-ctrl-switch').prop('checked', false); } } if ('bri' in event.args) { $light.find('.slider.bri').val(event.args.bri); } if ('sat' in event.args) { $light.find('.slider.sat').val(event.args.sat); } if ('hue' in event.args) { $light.find('.slider.hue').val(event.args.hue); } break; } }; var createPowerToggleElement = function(data) { var id = data['type'] + '_' + data['id']; var $powerToggle = $('
').addClass('toggle toggle--push light-ctrl-switch-container'); var $input = $('').attr('type', 'checkbox') .attr('id', id).addClass('toggle--checkbox'); if (type === 'animation') { $input.addClass('animation-switch'); } else { $input.addClass('light-ctrl-switch'); } data = data || {}; for (var attr of Object.keys(data)) { $input.data(attr, data[attr]); } var $label = $('').attr('for', id).addClass('toggle--btn'); $input.appendTo($powerToggle); $label.appendTo($powerToggle); if ('on' in data && data['on']) { $input.prop('checked', true); } return $powerToggle; }; var createColorSelector = function(data) { var type = data.type; var element; if (type === 'light') { element = lights[data.id]; } else if (type === 'room' || type === 'animation') { element = groups[data.id]; } else { throw "Unknown type: " + type; } var $colorSelector = $('
') .addClass('light-color-selector'); if (type === 'animation') { // Animation type selector var $typeContainer = $('
') .addClass('animation-type-container').addClass('row'); var $typeText = $('
').addClass('two columns').text('Type'); // Color transition type var $transitionTypeContainer = $('
').addClass('five columns'); var $transitionType = $('').addClass('animation-type') .addClass('one column').data('type', 'color_transition') .attr('id', 'hue-animation-color-transition').data('name', element.name) .attr('type', 'radio').attr('name', 'animation-type'); var $transitionTypeLabel = $('').attr('for', 'hue-animation-color-transition') .addClass('four columns').text('Color transition'); $typeText.appendTo($typeContainer); $transitionType.appendTo($transitionTypeContainer); $transitionTypeLabel.appendTo($transitionTypeContainer); $transitionTypeContainer.appendTo($typeContainer); // Blink type var $blinkTypeContainer = $('
').addClass('five columns'); var $blinkType = $('').addClass('animation-type') .addClass('one column').data('type', 'blink') .attr('id', 'hue-animation-blink').data('name', element.name) .attr('type', 'radio').attr('name', 'animation-type'); var $blinkTypeLabel = $('').attr('for', 'hue-animation-blink') .addClass('four columns').text('Blink'); $blinkType.appendTo($blinkTypeContainer); $blinkTypeLabel.appendTo($blinkTypeContainer); $blinkTypeContainer.appendTo($typeContainer); $typeContainer.appendTo($colorSelector); // Color transition container var $animationContainer = $('
') .addClass('animation-container row').data('animation-type', 'color_transition'); // Hue slider var $hueContainer = $('
') .addClass('slider-container').addClass('row'); var defaultHueRange = [0, 65535]; var $hueText = $('
').addClass('two columns').text('Hue range'); var $hueSlider = $('
') .addClass('ten columns').data('animation-property', 'hue_range') .data('id', data.id).val(defaultHueRange).slider({ range: true, min: 0, max: 65535, values: defaultHueRange, slide: function(event, ui) { var values = $(event.target).slider("option", "values"); $(this).val(values); } }); $hueText.appendTo($hueContainer); $hueSlider.appendTo($hueContainer); $hueContainer.appendTo($animationContainer); // Sat slider var $satContainer = $('
') .addClass('slider-container').addClass('row'); var defaultSatRange = [155, 255]; var $satText = $('
').addClass('two columns').text('Sat range'); var $satSlider = $('
') .addClass('ten columns').data('animation-property', 'sat_range') .data('id', data.id).val(defaultSatRange).slider({ range: true, min: 0, max: 255, values: defaultSatRange, slide: function(event, ui) { var values = $(event.target).slider("option", "values"); $(this).val(values); } }); $satText.appendTo($satContainer); $satSlider.appendTo($satContainer); $satContainer.appendTo($animationContainer); // Bri slider var $briContainer = $('
') .addClass('slider-container').addClass('row'); var defaultBriRange = [240, 255]; var $briText = $('
').addClass('two columns').text('Bri range'); var $briSlider = $('
') .addClass('ten columns').data('animation-property', 'bri_range') .data('id', data.id).val(defaultBriRange).slider({ range: true, min: 0, max: 255, values: defaultBriRange, slide: function(event, ui) { var values = $(event.target).slider("option", "values"); $(this).val(values); } }); $briText.appendTo($briContainer); $briSlider.appendTo($briContainer); $briContainer.appendTo($animationContainer); // Hue step var $hueStepContainer = $('
') .addClass('slider-container').addClass('row'); var $hueStepText = $('
').addClass('two columns').text('Hue step'); var $hueStepSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('hue').data('animation-property', 'hue_step') .attr('type', 'range').attr('min', 0).attr('max', 65535) .data('id', data.id).data('name', element.name).val(1000); $hueStepText.appendTo($hueStepContainer); $hueStepSlider.appendTo($hueStepContainer); $hueStepContainer.appendTo($animationContainer); // Sat step var $satStepContainer = $('
') .addClass('slider-container').addClass('row'); var $satStepText = $('
').addClass('two columns').text('Sat step'); var $satStepSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('sat').data('animation-property', 'sat_step') .attr('type', 'range').attr('min', 0).attr('max', 255) .data('id', data.id).data('name', element.name).val(2); $satStepText.appendTo($satStepContainer); $satStepSlider.appendTo($satStepContainer); $satStepContainer.appendTo($animationContainer); // Bri step var $briStepContainer = $('
') .addClass('slider-container').addClass('row'); var $briStepText = $('
').addClass('two columns').text('Bri step'); var $briStepSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('bri').data('animation-property', 'bri_step') .attr('type', 'range').attr('min', 0).attr('max', 255) .data('id', data.id).data('name', element.name).val(1); $briStepText.appendTo($briStepContainer); $briStepSlider.appendTo($briStepContainer); $briStepContainer.appendTo($animationContainer); // Transition seconds var $transitionContainer = $('
') .addClass('slider-container').addClass('row'); var $transitionText = $('
').addClass('two columns').text('Transition seconds'); var $transitionInput = $('').data('animation-property', 'transition_seconds') .addClass('two columns pull-right').attr('type', 'text') .data('id', data.id).data('name', element.name).val(1); $transitionText.appendTo($transitionContainer); $transitionInput.appendTo($transitionContainer); $transitionContainer.appendTo($animationContainer); // Duration seconds var $durationContainer = $('
') .addClass('slider-container').addClass('row'); var $durationText = $('
').addClass('two columns').text('Duration seconds'); var $durationInput = $('').data('animation-property', 'duration') .addClass('two columns pull-right').attr('type', 'text') .data('id', data.id).data('name', element.name); $durationText.appendTo($durationContainer); $durationInput.appendTo($durationContainer); $durationContainer.appendTo($animationContainer); $animationContainer.appendTo($colorSelector); // Blink animation container $animationContainer = $('
') .addClass('animation-container row').data('animation-type', 'blink'); // Transition seconds $transitionContainer = $('
') .addClass('slider-container').addClass('row'); $transitionText = $('
').addClass('two columns').text('Transition seconds'); $transitionInput = $('').data('animation-property', 'transition_seconds') .addClass('two columns pull-right').attr('type', 'text') .data('id', data.id).data('name', element.name).val(1); $transitionText.appendTo($transitionContainer); $transitionInput.appendTo($transitionContainer); $transitionContainer.appendTo($animationContainer); // Duration seconds $durationContainer = $('
').data('animation-property', 'duration') .addClass('slider-container').addClass('row'); $durationText = $('
').addClass('two columns').text('Duration seconds'); $durationInput = $('').data('animation-property', 'duration') .addClass('two columns pull-right').attr('type', 'text') .data('id', data.id).data('name', element.name); $durationText.appendTo($durationContainer); $durationInput.appendTo($durationContainer); $durationContainer.appendTo($animationContainer); $animationContainer.appendTo($colorSelector); } else { // Hue slider var $hueContainer = $('
') .addClass('slider-container').addClass('row'); var $hueText = $('
').addClass('two columns').text('Hue'); var $hueSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('hue').data('type', type) .attr('type', 'range').attr('min', 0).attr('max', 65535).data('property', 'hue') .data('id', data.id).data('name', element.name).val(type === 'light' ? element.state.hue : 0); $hueText.appendTo($hueContainer); $hueSlider.appendTo($hueContainer); $hueContainer.appendTo($colorSelector); // Saturation slider var $satContainer = $('
') .addClass('slider-container').addClass('row'); var $satText = $('
').addClass('two columns').text('Saturation'); var $satSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('sat').data('type', type) .attr('type', 'range').attr('min', 0).attr('max', 255).data('property', 'sat') .data('id', data.id).data('name', element.name).val(type === 'light' ? element.state.sat : 0); $satText.appendTo($satContainer); $satSlider.appendTo($satContainer); $satContainer.appendTo($colorSelector); // Brightness slider var $briContainer = $('
') .addClass('slider-container').addClass('row'); var $briText = $('
').addClass('two columns').text('Brightness'); var $briSlider = $('').addClass('slider light-slider') .addClass('ten columns').addClass('bri').data('type', type) .attr('type', 'range').attr('min', 0).attr('max', 255).data('property', 'bri') .data('id', data.id).data('name', element.name).val(type === 'light' ? element.state.bri : 0); $briText.appendTo($briContainer); $briSlider.appendTo($briContainer); $briContainer.appendTo($colorSelector); } return $colorSelector; }; var createLightCtrlElement = function(type, id) { var element; if (type === 'light') { element = lights[id]; } else if (type === 'room' || type === 'animation') { element = groups[id]; } else { throw "Unknown type: " + type; } var on; if (type === 'light') { on = element.state.on; } else if (type === 'room') { on = element.state.any_on; } else { on = false; } var $light = $('
') .addClass('light-item') .data('type', type) .data('id', id) .data('name', element.name) .data('on', on); if (type === 'room') { $light.addClass('all-lights-item'); } else if (type === 'animation') { $light.addClass('animation-item'); } var $row1 = $('
').addClass('row'); var $row2 = $('
').addClass('row'); var lightName; switch(type) { case 'light': lightName = element.name; break; case 'room': lightName = 'All Lights'; break; case 'animation': lightName = 'Animate'; break; } var $lightName = $('
') .addClass('light-item-name') .text(lightName); var $powerToggle = createPowerToggleElement({ type: type, id: id, on: on, }); var $colorSelector = createColorSelector({ type: type, id: id, }); $lightName.appendTo($row1); $powerToggle.appendTo($row1); $colorSelector.appendTo($row2); $row1.appendTo($light); $row2.appendTo($light); return $light; }; var updateRooms = function(rooms) { var roomByLight = {}; var roomsByScene = {}; $roomsList.html(''); $lightsList.html(''); $scenesList.html(''); for (var room of Object.keys(rooms)) { var $room = $('
') .addClass('room-item') .data('id', room) .data('name', rooms[room].name) .text(rooms[room].name); var $roomLights = $('
') .addClass('room-lights-item') .data('id', room); var $roomScenes = $('
') .addClass('room-scenes-item') .data('room-id', room) .data('room-name', rooms[room].name); $room.appendTo($roomsList); $roomLights.appendTo($lightsList); $roomScenes.appendTo($scenesList); for (var light of rooms[room].lights) { var $light = createLightCtrlElement(type='light', id=light); $light.appendTo($roomLights); roomByLight[light] = room; } roomByLight[light] = room; var $animation = createLightCtrlElement(type='animation', id=room); $animation.prependTo($roomLights); var $allLights = createLightCtrlElement(type='room', id=room); $allLights.prependTo($roomLights); } for (var scene of Object.keys(scenes)) { if (scenes[scene].name.match(/(on|off) \d+$/)) { // Old 1.0 scenes are saved as "scene_name on " but aren't visible // not settable through the app - ignore them continue; } roomsByScene[scene] = new Set(); for (var light of scenes[scene].lights) { var room = roomByLight[light]; if (roomsByScene[scene].has(room)) { continue; } roomsByScene[scene].add(room); var $roomScenes = $scenesList.find('.room-scenes-item') .filter(function(i, item) { return $(item).data('room-id') === room }); var $scene = $('
') .addClass('scene-item') .data('id', scene) .data('name', scenes[scene].name) .text(scenes[scene].name); $scene.appendTo($roomScenes); } } }; var initUi = function() { $.when( execute({ type: 'request', action: 'light.hue.get_lights' }), execute({ type: 'request', action: 'light.hue.get_groups' }), execute({ type: 'request', action: 'light.hue.get_scenes' }) ).done(function(l, g, s) { lights = l[0].response.output; groups = g[0].response.output; scenes = s[0].response.output; for (var group of Object.keys(groups)) { if (groups[group].type.toLowerCase() !== 'room') { delete groups[group]; } } updateRooms(groups); }).then(function() { initBindings(); }); }; var refreshStatus = function() { var onResponse = function(data) { var response = data.response.output; for (var light of Object.keys(response)) { var $element = $('.light-item').filter(function(i, item) { return $(item).data('type') === 'light' && $(item).data('id') === light }); $element.find('input.light-ctrl-switch').prop('checked', response[light].state.on); $element.find('input.hue').val(response[light].state.hue); $element.find('input.sat').val(response[light].state.sat); $element.find('input.bri').val(response[light].state.bri); } }; execute({ type: 'request', action: 'light.hue.get_lights' }, onResponse); }; var initBindings = function() { $roomsList.on('click touch', '.room-item', function() { $('.room-item').removeClass('selected'); $('.room-lights-item').hide(); $('.room-scenes-item').hide(); var roomId = $(this).data('id'); var $roomLights = $('.room-lights-item').filter(function(i, item) { return $(item).data('id') === roomId }); var $roomScenes = $('.room-scenes-item').filter(function(i, item) { return $(item).data('room-id') === roomId }); $(this).addClass('selected'); $roomLights.show(); $roomScenes.show(); }); $scenesList.on('click touch', '.scene-item', function() { $('.scene-item').removeClass('selected'); $(this).addClass('selected'); execute({ type: 'request', action: 'light.hue.scene', args: { name: $(this).data('name') } }, refreshStatus); }); $lightsList.on('click touch', '.light-item-name', function() { var $lightItem = $(this).parents('.light-item'); var $colorSelector = $lightItem.find('.light-color-selector'); $('.light-color-selector').hide(); $colorSelector.toggle(); $('.light-item').removeClass('selected'); $lightItem.addClass('selected'); }); $lightsList.on('click touch', '.light-ctrl-switch', function(e) { e.stopPropagation(); var $lightItem = $($(this).parents('.light-item')); var type = $lightItem.data('type'); var name = $lightItem.data('name'); var isOn = $lightItem.data('on'); var action = 'light.hue.' + (isOn ? 'off' : 'on'); var key = (type == 'light' ? 'lights' : 'groups'); var args = { type: 'request', action: action, args: {} }; args['args'][key] = [name]; execute(args, function() { $lightItem.data('on', !isOn); refreshStatus(); }); }); $lightsList.on('click touch', '.animation-switch', function(e) { e.stopPropagation(); var turnedOn = $(this).prop('checked'); var args = {}; args['groups'] = $(this).parents('.animation-item').data('name'); args['animation'] = $(this).parents('.animation-item') .find('input.animation-type:checked').data('type'); var $animationCtrl = $(this).parents('.animation-item') .find('.animation-container').filter( (index, node) => $(node).data('animation-type') === args['animation'] ); var params = $animationCtrl.find('*').filter( (index, node) => $(node).data('animation-property')) .toArray().reduce( (map, input) => { if ($(input).val().length) { var val = $(input).val(); val = Array.isArray(val) ? val.map((i) => parseFloat(i)) : parseFloat(val); map[$(input).data('animation-property')] = val; } return map }, {} ); for (var p of Object.keys(params)) { args[p] = params[p]; } if (turnedOn) { execute( { type: 'request', action: 'light.hue.animate', args: args, }, onSuccess = function() { $(this).prop('checked', true); } ); } else { execute( { type: 'request', action: 'light.hue.stop_animation', }, onSuccess = function() { $(this).prop('checked', false); } ); } }); $lightsList.on('mouseup touchend', '.light-slider', function() { var property = $(this).data('property'); var type = $(this).data('type'); var name = $(this).data('name'); var args = { type: 'request', action: 'light.hue.' + property, args: { value: $(this).val() } }; if (type === 'light') { args.args.lights = [name]; } else { args.args.groups = [name]; } execute(args, refreshStatus); }); $lightsList.on('click touch', 'input.animation-type', function(e) { var type = $(this).data('type'); var $animationContainers = $(this).parents('.animation-item').find('.animation-container') var $animationContainer = $(this).parents('.animation-item').find('.animation-container') .filter(function() { return $(this).data('animationType') === type }) $animationContainers.hide(); $animationContainer.show(); }); if (window.config.light.hue.default_group) { var $defaultRoomItem = $roomsList.find('.room-item').filter( (i, r) => $(r).data('name') == window.config.light.hue.default_group); $defaultRoomItem.click(); } }; var initEvents = function() { window.registerEventListener(onEvent); }; var init = function() { initUi(); initEvents(); }; init(); });