Support for subscribe-once/unsubscribe frontend events mechanisms

This commit is contained in:
Fabio Manganiello 2020-12-15 00:01:28 +01:00
parent 0db997c6a0
commit 5d4f4b0378
46 changed files with 173 additions and 75 deletions

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>platypush</title><link href="/static/css/chunk-014e8b04.542f4068.css" rel="prefetch"><link href="/static/css/chunk-16a3f845.1df61c27.css" rel="prefetch"><link href="/static/css/chunk-24ff873d.5ef32028.css" rel="prefetch"><link href="/static/css/chunk-4bbbb9a3.431b3300.css" rel="prefetch"><link href="/static/css/chunk-5710a9bc.763b29ed.css" rel="prefetch"><link href="/static/css/chunk-62a3d08e.495b15c5.css" rel="prefetch"><link href="/static/css/chunk-ac6aae98.f24d8093.css" rel="prefetch"><link href="/static/css/chunk-e8078048.6c400707.css" rel="prefetch"><link href="/static/js/chunk-014e8b04.7f400c2d.js" rel="prefetch"><link href="/static/js/chunk-16a3f845.59b58d41.js" rel="prefetch"><link href="/static/js/chunk-24ff873d.f955ad3b.js" rel="prefetch"><link href="/static/js/chunk-2d2091df.ec2fb649.js" rel="prefetch"><link href="/static/js/chunk-4bbbb9a3.6f0e4975.js" rel="prefetch"><link href="/static/js/chunk-5710a9bc.47bb3f2d.js" rel="prefetch"><link href="/static/js/chunk-62a3d08e.8fc4fd3a.js" rel="prefetch"><link href="/static/js/chunk-ac6aae98.04b7413c.js" rel="prefetch"><link href="/static/js/chunk-e8078048.e668de5f.js" rel="prefetch"><link href="/static/css/app.5408c936.css" rel="preload" as="style"><link href="/static/css/chunk-vendors.5dad8b00.css" rel="preload" as="style"><link href="/static/js/app.fd969252.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.6eaf6fa5.js" rel="preload" as="script"><link href="/static/css/chunk-vendors.5dad8b00.css" rel="stylesheet"><link href="/static/css/app.5408c936.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.6eaf6fa5.js"></script><script src="/static/js/app.fd969252.js"></script></body></html> <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>platypush</title><link href="/static/css/chunk-24ff873d.5ef32028.css" rel="prefetch"><link href="/static/css/chunk-35b45d59.bea59a51.css" rel="prefetch"><link href="/static/css/chunk-45939517.1062df39.css" rel="prefetch"><link href="/static/css/chunk-4bbbb9a3.431b3300.css" rel="prefetch"><link href="/static/css/chunk-53360c78.2281ab32.css" rel="prefetch"><link href="/static/css/chunk-62a3d08e.495b15c5.css" rel="prefetch"><link href="/static/css/chunk-6fa461b6.1fb05517.css" rel="prefetch"><link href="/static/css/chunk-e8078048.6c400707.css" rel="prefetch"><link href="/static/js/chunk-24ff873d.f955ad3b.js" rel="prefetch"><link href="/static/js/chunk-2d2091df.8d32d3ba.js" rel="prefetch"><link href="/static/js/chunk-35b45d59.d541d43f.js" rel="prefetch"><link href="/static/js/chunk-45939517.38162e50.js" rel="prefetch"><link href="/static/js/chunk-4bbbb9a3.6f0e4975.js" rel="prefetch"><link href="/static/js/chunk-53360c78.54e2e626.js" rel="prefetch"><link href="/static/js/chunk-62a3d08e.8fc4fd3a.js" rel="prefetch"><link href="/static/js/chunk-6fa461b6.d6fffa0d.js" rel="prefetch"><link href="/static/js/chunk-e8078048.e668de5f.js" rel="prefetch"><link href="/static/css/app.5408c936.css" rel="preload" as="style"><link href="/static/css/chunk-vendors.5dad8b00.css" rel="preload" as="style"><link href="/static/js/app.41ee3441.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.1eac7b43.js" rel="preload" as="script"><link href="/static/css/chunk-vendors.5dad8b00.css" rel="stylesheet"><link href="/static/css/app.5408c936.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.1eac7b43.js"></script><script src="/static/js/app.41ee3441.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-45939517"],{"1cb0":function(e,t,s){"use strict";s("5eaa")},"2e0b":function(e,t,s){"use strict";s("e458")},3737:function(e,t,s){"use strict";s.r(t);s("b64b");var a=s("7a23"),n=Object(a["J"])("data-v-d6e48dfa");Object(a["u"])("data-v-d6e48dfa");var r={class:"date-time-weather"},i={class:"row date-time-container"},o={class:"row weather-container"},c={class:"row sensors-container"},u={key:0,class:"row"},h={class:"col-3"},d=Object(a["h"])("div",{class:"col-6"}," ",-1),l={class:"col-3"};Object(a["s"])();var m=n((function(e,t,s,n,m,b){var f=Object(a["z"])("DateTime"),w=Object(a["z"])("Weather"),j=Object(a["z"])("Sensor");return Object(a["r"])(),Object(a["e"])("div",r,[Object(a["h"])("div",i,[b._showDate||b._showTime?(Object(a["r"])(),Object(a["e"])(f,{key:0,"show-date":b._showDate,"show-time":b._showTime,"show-seconds":b._showSeconds,animate:s.animate},null,8,["show-date","show-time","show-seconds","animate"])):Object(a["f"])("",!0)]),Object(a["h"])("div",o,[s.showWeather?(Object(a["r"])(),Object(a["e"])(w,{key:0,"show-summary":b._showSummary,animate:b._animate,"icon-size":s.iconSize,"refresh-seconds":s.weatherRefreshSeconds},null,8,["show-summary","animate","icon-size","refresh-seconds"])):Object(a["f"])("",!0)]),Object(a["h"])("div",c,[b._showSensors&&Object.keys(e.sensors).length?(Object(a["r"])(),Object(a["e"])("div",u,[Object(a["h"])("div",h,[null!=e.sensors.temperature?(Object(a["r"])(),Object(a["e"])(j,{key:0,"icon-class":"fas fa-thermometer-half",value:e.sensors.temperature,unit:"°"},null,8,["value"])):Object(a["f"])("",!0)]),d,Object(a["h"])("div",l,[null!=e.sensors.humidity?(Object(a["r"])(),Object(a["e"])(j,{key:0,"icon-class":"fas fa-tint",value:e.sensors.humidity,unit:"%"},null,8,["value"])):Object(a["f"])("",!0)])])):Object(a["f"])("",!0)])])})),b=(s("a9e3"),s("3e54")),f=s("365a"),w=s("5b43"),j=(s("b0c0"),Object(a["J"])("data-v-1efb373e"));Object(a["u"])("data-v-1efb373e");var O={class:"sensor"},p={key:0,class:"label-container col-6"},v={class:"value-container col-6"};Object(a["s"])();var y=j((function(e,t,s,n,r,i){return Object(a["r"])(),Object(a["e"])("div",O,[s.iconClass||s.name?(Object(a["r"])(),Object(a["e"])("div",p,[s.iconClass?(Object(a["r"])(),Object(a["e"])("i",{key:0,class:s.iconClass},null,2)):s.name?(Object(a["r"])(),Object(a["e"])("span",{key:1,textContent:Object(a["C"])(s.name)},null,8,["textContent"])):Object(a["f"])("",!0)])):Object(a["f"])("",!0),Object(a["h"])("div",v,[Object(a["h"])("span",{class:"value",textContent:Object(a["C"])(i._value)},null,8,["textContent"])])])})),S=(s("99af"),s("b680"),{name:"Sensor",props:{iconClass:{type:String,required:!1},name:{type:String,required:!1},value:{required:!1},unit:{type:String,required:!1},decimals:{type:Number,required:!1,default:1},isBoolean:{type:Boolean,required:!1,default:!1}},computed:{_value:function(){if(null==this.value)return"N/A";if(this.isBoolean)return this.parseBoolean(this.value);var e=parseFloat(this.value);return null!=this.decimals&&(e=e.toFixed(this.decimals)),this.unit&&(e="".concat(e).concat(this.unit)),e}}});s("2e0b");S.render=y,S.__scopeId="data-v-1efb373e";var _=S,q={name:"DateTimeWeather",mixins:[b["a"]],components:{Sensor:_,DateTime:f["default"],Weather:w["default"]},props:{animate:{required:!1,default:!0},iconSize:{type:Number,required:!1,default:50},showDate:{required:!1,default:!0},showTime:{required:!1,default:!0},showWeather:{required:!1,default:!0},showSummary:{required:!1,default:!0},showSensors:{required:!1,default:!0},showSeconds:{required:!1,default:!0},sensorTemperatureAttr:{type:String,required:!1,default:"temperature"},sensorHumidityAttr:{type:String,required:!1,default:"humidity"},weatherRefreshSeconds:{type:Number,required:!1,default:900}},computed:{_showDate:function(){return this.parseBoolean(this.showDate)},_showTime:function(){return this.parseBoolean(this.showTime)},_showSeconds:function(){return this.parseBoolean(this.showSeconds)},_showWeather:function(){return this.parseBoolean(this.showWeather)},_showSummary:function(){return this.parseBoolean(this.showSummary)},_showSensors:function(){return this.parseBoolean(this.showSensors)},_animate:function(){return this.parseBoolean(this.animate)}},data:function(){return{sensors:{}}},methods:{onSensorData:function(e){this.sensorTemperatureAttr in e.data&&(this.sensors.temperature=e.data.temperature),this.sensorHumidityAttr in e.data&&(this.sensors.humidity=e.data.humidity)}},mounted:function(){this.subscribe(this.onSensorData,null,"platypush.message.event.sensor.SensorDataChangeEvent")}};s("1cb0");q.render=m,q.__scopeId="data-v-d6e48dfa";t["default"]=q},"5eaa":function(e,t,s){},e458:function(e,t,s){}}]);
//# sourceMappingURL=chunk-45939517.38162e50.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-5710a9bc"],{"2e0b":function(e,t,s){"use strict";s("e458")},3737:function(e,t,s){"use strict";s.r(t);s("b64b");var a=s("7a23"),n=Object(a["J"])("data-v-6bc0bd70");Object(a["u"])("data-v-6bc0bd70");var r={class:"date-time-weather"},i={class:"row date-time-container"},o={class:"row weather-container"},c={class:"row sensors-container"},u={key:0,class:"row"},d={class:"col-3"},h=Object(a["h"])("div",{class:"col-6"}," ",-1),l={class:"col-3"};Object(a["s"])();var b=n((function(e,t,s,n,b,m){var f=Object(a["z"])("DateTime"),w=Object(a["z"])("Weather"),j=Object(a["z"])("Sensor");return Object(a["r"])(),Object(a["e"])("div",r,[Object(a["h"])("div",i,[m._showDate||m._showTime?(Object(a["r"])(),Object(a["e"])(f,{key:0,"show-date":m._showDate,"show-time":m._showTime,"show-seconds":m._showSeconds,animate:s.animate},null,8,["show-date","show-time","show-seconds","animate"])):Object(a["f"])("",!0)]),Object(a["h"])("div",o,[s.showWeather?(Object(a["r"])(),Object(a["e"])(w,{key:0,"show-summary":m._showSummary,animate:m._animate,"icon-size":s.iconSize,"refresh-seconds":s.weatherRefreshSeconds},null,8,["show-summary","animate","icon-size","refresh-seconds"])):Object(a["f"])("",!0)]),Object(a["h"])("div",c,[m._showSensors&&Object.keys(e.sensors).length?(Object(a["r"])(),Object(a["e"])("div",u,[Object(a["h"])("div",d,[null!=e.sensors.temperature?(Object(a["r"])(),Object(a["e"])(j,{key:0,"icon-class":"fas fa-thermometer-half",value:e.sensors.temperature,unit:"°"},null,8,["value"])):Object(a["f"])("",!0)]),h,Object(a["h"])("div",l,[null!=e.sensors.humidity?(Object(a["r"])(),Object(a["e"])(j,{key:0,"icon-class":"fas fa-tint",value:e.sensors.humidity,unit:"%"},null,8,["value"])):Object(a["f"])("",!0)])])):Object(a["f"])("",!0)])])})),m=(s("a9e3"),s("3e54")),f=s("365a"),w=s("5b43"),j=(s("b0c0"),Object(a["J"])("data-v-1efb373e"));Object(a["u"])("data-v-1efb373e");var O={class:"sensor"},p={key:0,class:"label-container col-6"},v={class:"value-container col-6"};Object(a["s"])();var y=j((function(e,t,s,n,r,i){return Object(a["r"])(),Object(a["e"])("div",O,[s.iconClass||s.name?(Object(a["r"])(),Object(a["e"])("div",p,[s.iconClass?(Object(a["r"])(),Object(a["e"])("i",{key:0,class:s.iconClass},null,2)):s.name?(Object(a["r"])(),Object(a["e"])("span",{key:1,textContent:Object(a["C"])(s.name)},null,8,["textContent"])):Object(a["f"])("",!0)])):Object(a["f"])("",!0),Object(a["h"])("div",v,[Object(a["h"])("span",{class:"value",textContent:Object(a["C"])(i._value)},null,8,["textContent"])])])})),S=(s("99af"),s("b680"),{name:"Sensor",props:{iconClass:{type:String,required:!1},name:{type:String,required:!1},value:{required:!1},unit:{type:String,required:!1},decimals:{type:Number,required:!1,default:1},isBoolean:{type:Boolean,required:!1,default:!1}},computed:{_value:function(){if(null==this.value)return"N/A";if(this.isBoolean)return this.parseBoolean(this.value);var e=parseFloat(this.value);return null!=this.decimals&&(e=e.toFixed(this.decimals)),this.unit&&(e="".concat(e).concat(this.unit)),e}}});s("2e0b");S.render=y,S.__scopeId="data-v-1efb373e";var _=S,q={name:"DateTimeWeather",mixins:[m["a"]],components:{Sensor:_,DateTime:f["default"],Weather:w["default"]},props:{animate:{required:!1,default:!0},iconSize:{type:Number,required:!1,default:50},showDate:{required:!1,default:!0},showTime:{required:!1,default:!0},showWeather:{required:!1,default:!0},showSummary:{required:!1,default:!0},showSensors:{required:!1,default:!0},showSeconds:{required:!1,default:!0},sensorTemperatureAttr:{type:String,required:!1,default:"temperature"},sensorHumidityAttr:{type:String,required:!1,default:"humidity"},weatherRefreshSeconds:{type:Number,required:!1,default:900}},computed:{_showDate:function(){return this.parseBoolean(this.showDate)},_showTime:function(){return this.parseBoolean(this.showTime)},_showSeconds:function(){return this.parseBoolean(this.showSeconds)},_showWeather:function(){return this.parseBoolean(this.showWeather)},_showSummary:function(){return this.parseBoolean(this.showSummary)},_showSensors:function(){return this.parseBoolean(this.showSensors)},_animate:function(){return this.parseBoolean(this.animate)}},data:function(){return{sensors:{}}},methods:{onSensorData:function(e){this.sensorTemperatureAttr in e.data&&(this.sensors.temperature=e.data.temperature),this.sensorHumidityAttr in e.data&&(this.sensors.humidity=e.data.humidity)}},mounted:function(){this.subscribe(this.onSensorData,"platypush.message.event.sensor.SensorDataChangeEvent")}};s("cd6d");q.render=b,q.__scopeId="data-v-6bc0bd70";t["default"]=q},"5d41":function(e,t,s){},cd6d:function(e,t,s){"use strict";s("5d41")},e458:function(e,t,s){}}]);
//# sourceMappingURL=chunk-5710a9bc.47bb3f2d.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -23,6 +23,7 @@ export default {
timeout: null, timeout: null,
reconnectMsecs: 30000, reconnectMsecs: 30000,
handlers: {}, handlers: {},
handlerNameToEventTypes: {},
} }
}, },
@ -60,7 +61,7 @@ export default {
} }
if (event.args.type in this.handlers) { if (event.args.type in this.handlers) {
handlers.push(...this.handlers[event.args.type]) handlers.push(...Object.values(this.handlers[event.args.type]))
} }
for (let handler of handlers) { for (let handler of handlers) {
@ -134,32 +135,40 @@ export default {
subscribe(msg) { subscribe(msg) {
const handler = msg.handler const handler = msg.handler
const events = msg.events.length ? msg.events : [null] const events = msg.events.length ? msg.events : [null]
const handlerName = msg.handlerName
for (const event of events) { for (const event of events) {
if (!(event in this.handlers)) { if (!(event in this.handlers)) {
this.handlers[event] = [] this.handlers[event] = {}
} }
this.handlers[event].push(handler) if (!(handlerName in this.handlerNameToEventTypes)) {
this.handlerNameToEventTypes[handlerName] = events
}
this.handlers[event][handlerName] = handler
}
return () => {
this.unsubscribe(handlerName)
} }
}, },
unsubscribe(msg) { unsubscribe(handlerName) {
const handler = msg.handler const events = this.handlerNameToEventTypes[handlerName]
const events = msg.events.length ? msg.events : [null] if (!events)
return
for (const event of events) { for (const event of events) {
if (!(event in this.handlers)) if (!this.handlers[event]?.[handlerName])
continue continue
const idx = this.handlers[event].indexOf(handler) delete this.handlers[event][handlerName]
if (idx < 0) if (!Object.keys(this.handlers[event]).length)
continue
this.handlers[event] = this.handlers[event].splice(idx, 1)[1]
if (!this.handlers[event].length)
delete this.handlers[event] delete this.handlers[event]
} }
delete this.handlerNameToEventTypes[handlerName]
}, },
}, },

View File

@ -30,8 +30,7 @@
<i class="icon far fa-image" /> <i class="icon far fa-image" />
<span class="view-title">&nbsp; Scenes</span> <span class="view-title">&nbsp; Scenes</span>
</button> </button>
<button :class="{selected: selectedView === 'animate'}" title="Animate" <button :class="{selected: selectedView === 'animate'}" title="Animate" @click="selectedView = 'animate'">
@click="selectedView = 'animate'">
<i class="icon fas fa-video" /> <i class="icon fas fa-video" />
<span class="view-title">&nbsp; Animate</span> <span class="view-title">&nbsp; Animate</span>
</button> </button>

View File

@ -25,7 +25,7 @@ export default {
}, },
mounted() { mounted() {
this.subscribe(this.onMessage, 'platypush.message.event.pushbullet.PushbulletEvent') this.subscribe(this.onMessage, null, 'platypush.message.event.pushbullet.PushbulletEvent')
}, },
} }
</script> </script>

View File

@ -105,12 +105,12 @@ export default {
}, },
registerHandlers() { registerHandlers() {
this.subscribe(this.conversationStart, 'platypush.message.event.assistant.ConversationStartEvent') this.subscribe(this.conversationStart, null, 'platypush.message.event.assistant.ConversationStartEvent')
this.subscribe(this.alertOn, 'platypush.message.event.assistant.AlertStartedEvent') this.subscribe(this.alertOn, null, 'platypush.message.event.assistant.AlertStartedEvent')
this.subscribe(this.alertOff, 'platypush.message.event.assistant.AlertEndEvent') this.subscribe(this.alertOff, null, 'platypush.message.event.assistant.AlertEndEvent')
this.subscribe(this.speechRecognized, 'platypush.message.event.assistant.SpeechRecognizedEvent') this.subscribe(this.speechRecognized, null, 'platypush.message.event.assistant.SpeechRecognizedEvent')
this.subscribe(this.response, 'platypush.message.event.assistant.ResponseEvent') this.subscribe(this.response, null, 'platypush.message.event.assistant.ResponseEvent')
this.subscribe(this.conversationEnd, this.subscribe(this.conversationEnd, null,
'platypush.message.event.assistant.ConversationEndEvent', 'platypush.message.event.assistant.ConversationEndEvent',
'platypush.message.event.assistant.NoResponseEvent', 'platypush.message.event.assistant.NoResponseEvent',
'platypush.message.event.assistant.ConversationTimeoutEvent') 'platypush.message.event.assistant.ConversationTimeoutEvent')

View File

@ -6,7 +6,7 @@
</div> </div>
<div class="panel" v-else> <div class="panel" v-else>
<Group :group="groups[selectedGroup]" :lights="displayedLights" :scenes="scenesByGroup[selectedGroup]" <Group :group="groups[selectedGroup]" :lights="displayedLights" :scenes="scenesByGroup[selectedGroup]"
:color-converter="colorConverter" :animations="animationsByGroup[selectedGroup]" @close="closeGroup" :color-converter="colorConverter" :animations="animationsByGroup[selectedGroup]" @close="selectedGroup = null"
@light-toggle="$emit('light-toggle', $event)" @group-toggle="$emit('group-toggle', $event)" @light-toggle="$emit('light-toggle', $event)" @group-toggle="$emit('group-toggle', $event)"
@set-light="$emit('set-light', $event)" @set-light="$emit('set-light', $event)"
@set-group="$emit('set-group', {groupId: selectedGroup, value: $event})" @set-group="$emit('set-group', {groupId: selectedGroup, value: $event})"
@ -30,7 +30,8 @@ export default {
name: "Light", name: "Light",
components: {Group, Groups}, components: {Group, Groups},
mixins: [Utils, Panel], mixins: [Utils, Panel],
emits: ['group-toggle', 'light-toggle', 'set-light', 'set-group', 'select-scene', 'start-animation', 'stop-animation'], emits: ['group-toggle', 'light-toggle', 'set-light', 'set-group', 'select-scene', 'start-animation', 'stop-animation',
'refresh'],
props: { props: {
lights: { lights: {
@ -168,14 +169,50 @@ export default {
}) })
}, },
closeGroup() { refresh() {
this.selectedGroup = null this.$emit('refresh')
},
onLightChange(event) {
if (event.plugin_name !== this.pluginName)
return
if (!this.lights[event.light_id]) {
this.refresh()
return
}
delete event.plugin_name
delete event.type
this.lights[event.light_id].state = {
...(this.lights[event.light_id]?.state || {}),
...event,
}
},
onAnimationChange(event) {
if (event.plugin_name !== this.pluginName)
return
this.refresh()
}, },
}, },
mounted() { mounted() {
this.subscribe(this.onLightChange, 'on-light-change',
'platypush.message.event.light.LightStatusChangeEvent')
this.subscribe(this.onAnimationChange, 'on-animation-change',
'platypush.message.event.light.LightAnimationStartedEvent',
'platypush.message.event.light.LightAnimationStoppedEvent')
this.initSelectedGroup() this.initSelectedGroup()
}, },
destroyed() {
this.unsubscribe('on-light-change')
this.unsubscribe('on-animation-change')
},
} }
</script> </script>

View File

@ -4,7 +4,7 @@
:animations="animations" :initial-group="initialGroup" :loading-groups="loadingGroups" :animations="animations" :initial-group="initialGroup" :loading-groups="loadingGroups"
:color-converter="colorConverter" @group-toggle="toggleGroup" :color-converter="colorConverter" @group-toggle="toggleGroup"
@light-toggle="toggleLight" @set-light="setLight" @set-group="setGroup" @select-scene="setScene" @light-toggle="toggleLight" @set-light="setLight" @set-group="setGroup" @select-scene="setScene"
@start-animation="startAnimation" @stop-animation="stopAnimation" /> @start-animation="startAnimation" @stop-animation="stopAnimation" @refresh="refresh(true)"/>
</template> </template>
<script> <script>

View File

@ -161,7 +161,7 @@ export default {
}, },
mounted() { mounted() {
this.subscribe(this.onSensorData, 'platypush.message.event.sensor.SensorDataChangeEvent'); this.subscribe(this.onSensorData, null, 'platypush.message.event.sensor.SensorDataChangeEvent');
}, },
} }
</script> </script>

View File

@ -289,16 +289,16 @@ export default {
setInterval(this.refresh, parseInt((this.refreshSeconds*1000).toFixed(0))) setInterval(this.refresh, parseInt((this.refreshSeconds*1000).toFixed(0)))
} }
this.subscribe(this.onNewPlayingTrack, 'platypush.message.event.music.NewPlayingTrackEvent') this.subscribe(this.onNewPlayingTrack, 'widget-music-on-new-track', 'platypush.message.event.music.NewPlayingTrackEvent')
this.subscribe(this.onMusicStop, 'platypush.message.event.music.MusicStopEvent') this.subscribe(this.onMusicStop, 'widget-music-on-music-stop', 'platypush.message.event.music.MusicStopEvent')
this.subscribe(this.onMusicPlay, 'platypush.message.event.music.MusicPlayEvent') this.subscribe(this.onMusicPlay, 'widget-music-on-music-play', 'platypush.message.event.music.MusicPlayEvent')
this.subscribe(this.onMusicPause, 'platypush.message.event.music.MusicPauseEvent') this.subscribe(this.onMusicPause, 'widget-music-on-music-pause', 'platypush.message.event.music.MusicPauseEvent')
this.subscribe(this.onSeekChange, 'platypush.message.event.music.SeekChangeEvent') this.subscribe(this.onSeekChange, 'widget-music-on-music-seek', 'platypush.message.event.music.SeekChangeEvent')
this.subscribe(this.onVolumeChange, 'platypush.message.event.music.VolumeChangeEvent') this.subscribe(this.onVolumeChange, 'widget-music-on-volume-change', 'platypush.message.event.music.VolumeChangeEvent')
this.subscribe(this.onRepeatChange, 'platypush.message.event.music.PlaybackRepeatModeChangeEvent') this.subscribe(this.onRepeatChange, 'widget-music-on-repeat-change', 'platypush.message.event.music.PlaybackRepeatModeChangeEvent')
this.subscribe(this.onRandomChange, 'platypush.message.event.music.PlaybackRandomModeChangeEvent') this.subscribe(this.onRandomChange, 'widget-music-on-random-change', 'platypush.message.event.music.PlaybackRandomModeChangeEvent')
this.subscribe(this.onConsumeChange, 'platypush.message.event.music.PlaybackConsumeModeChangeEvent') this.subscribe(this.onConsumeChange, 'widget-music-on-consume-change', 'platypush.message.event.music.PlaybackConsumeModeChangeEvent')
this.subscribe(this.onSingleChange, 'platypush.message.event.music.PlaybackSingleModeChangeEvent') this.subscribe(this.onSingleChange, 'widget-music-on-single-change', 'platypush.message.event.music.PlaybackSingleModeChangeEvent')
}, },
} }
</script> </script>

View File

@ -116,7 +116,7 @@ export default {
mounted: function() { mounted: function() {
this.refresh() this.refresh()
this.subscribe(this.onWeatherChange, 'platypush.message.event.weather.NewWeatherConditionEvent') this.subscribe(this.onWeatherChange, null, 'platypush.message.event.weather.NewWeatherConditionEvent')
setInterval(this.refresh, parseInt((this.refreshSeconds*1000).toFixed(0))) setInterval(this.refresh, parseInt((this.refreshSeconds*1000).toFixed(0)))
}, },
} }

View File

@ -10,11 +10,12 @@ export default {
}, },
methods: { methods: {
subscribe(handler, ...events) { subscribe(handler, handlerName, ...events) {
const subFunc = () => { const subFunc = () => {
bus.emit('subscribe', { bus.emit('subscribe', {
events: events, events: events,
handler: handler, handler: handler,
handlerName: handlerName || this.generateId(),
}) })
} }
@ -31,6 +32,14 @@ export default {
} }
}) })
}, },
unsubscribe(handlerName) {
bus.emit('unsubscribe', handlerName)
},
generateId() {
return btoa([...Array(16).keys()].forEach(() => String.fromCharCode(Math.round(Math.random() * 255))))
},
} }
} }
</script> </script>

View File

@ -36,8 +36,8 @@ class LightHueBackend(Backend):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.poll_seconds = poll_seconds self.poll_seconds = poll_seconds
@staticmethod
def _get_lights(self): def _get_lights():
plugin = get_plugin('light.hue') plugin = get_plugin('light.hue')
if not plugin: if not plugin:
plugin = get_plugin('light.hue', reload=True) plugin = get_plugin('light.hue', reload=True)
@ -67,8 +67,11 @@ class LightHueBackend(Backend):
event_args['hue'] = state.get('hue') event_args['hue'] = state.get('hue')
if 'ct' in state and state.get('ct') != prev_state.get('ct'): if 'ct' in state and state.get('ct') != prev_state.get('ct'):
event_args['ct'] = state.get('ct') event_args['ct'] = state.get('ct')
if 'xy' in state and state.get('xy') != prev_state.get('xy'):
event_args['xy'] = state.get('xy')
if event_args: if event_args:
event_args['plugin_name'] = 'light.hue'
event_args['light_id'] = light_id event_args['light_id'] = light_id
event_args['light_name'] = light.get('name') event_args['light_name'] = light.get('name')
self.bus.post(LightStatusChangeEvent(**event_args)) self.bus.post(LightStatusChangeEvent(**event_args))
@ -93,4 +96,5 @@ class LightHueBackend(Backend):
self.logger.exception(e) self.logger.exception(e)
time.sleep(self.poll_seconds) time.sleep(self.poll_seconds)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -1,13 +1,25 @@
from typing import Optional
from platypush.message.event import Event from platypush.message.event import Event
class LightStatusChangeEvent(Event): class LightEvent(Event):
"""
Base class for light plugins events.
"""
def __init__(self, *args, plugin_name: Optional[str] = None, **kwargs):
"""
:param plugin_name: Name of the :class:`platypush.plugins.light.LightPlugin` instance that triggered the event.
"""
super().__init__(*args, plugin_name=plugin_name, **kwargs)
class LightStatusChangeEvent(LightEvent):
""" """
Event triggered when the state of a lightbulb changes Event triggered when the state of a lightbulb changes
""" """
def __init__(self, light_id=None, light_name=None, on=None, bri=None, def __init__(self, light_id=None, light_name=None, on=None, bri=None,
sat=None, hue=None, ct=None, *args, **kwargs): sat=None, hue=None, ct=None, xy=None, *args, **kwargs):
""" """
:param light_id: Light ID that triggered the event :param light_id: Light ID that triggered the event
:type light_id: int :type light_id: int
@ -29,6 +41,9 @@ class LightStatusChangeEvent(Event):
:param ct: Set if the color temperature state of the bulb changed :param ct: Set if the color temperature state of the bulb changed
:type ct: int :type ct: int
:param xy: Set if the color of the bulb (expressed in XY coordinates) has changed
:type xy: list
""" """
attrs = {} attrs = {}
@ -47,9 +62,26 @@ class LightStatusChangeEvent(Event):
attrs['hue'] = hue attrs['hue'] = hue
if ct is not None: if ct is not None:
attrs['ct'] = ct attrs['ct'] = ct
if xy is not None:
attrs['xy'] = xy
super().__init__(*args, **attrs, **kwargs) super().__init__(*args, **attrs, **kwargs)
# vim:sw=4:ts=4:et: class LightAnimationStartedEvent(LightEvent):
"""
Event triggered when a light animation is started.
"""
def __init__(self, *args, animation, lights: Optional[list] = None, groups: Optional[list] = None, **kwargs):
super().__init__(*args, animation=animation, lights=lights, groups=groups, **kwargs)
class LightAnimationStoppedEvent(LightEvent):
"""
Event triggered when a light animation is stopped.
"""
def __init__(self, *args, animation=None, lights: Optional[list] = None, groups: Optional[list] = None, **kwargs):
super().__init__(*args, animation=animation, lights=lights, groups=groups, **kwargs)
# vim:sw=4:ts=4:et:

View File

@ -5,6 +5,8 @@ import time
from enum import Enum from enum import Enum
from threading import Thread, Event from threading import Thread, Event
from platypush.context import get_bus
from platypush.message.event.light import LightAnimationStartedEvent, LightAnimationStoppedEvent
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.light import LightPlugin from platypush.plugins.light import LightPlugin
from platypush.utils import set_thread_name from platypush.utils import set_thread_name
@ -17,6 +19,12 @@ class LightHuePlugin(LightPlugin):
Requires: Requires:
* **phue** (``pip install phue``) * **phue** (``pip install phue``)
Triggers:
- :class:`platypush.message.event.light.LightAnimationStartedEvent` when an animation is started.
- :class:`platypush.message.event.light.LightAnimationStoppedEvent` when an animation is stopped.
""" """
MAX_BRI = 255 MAX_BRI = 255
@ -851,7 +859,7 @@ class LightHuePlugin(LightPlugin):
def _animate_thread(lights): def _animate_thread(lights):
set_thread_name('HueAnimate') set_thread_name('HueAnimate')
self.logger.info('Starting {} animation'.format(animation, (lights or groups))) get_bus().post(LightAnimationStartedEvent(lights=lights, groups=groups, animation=animation))
lights = _initialize_light_attrs(lights) lights = _initialize_light_attrs(lights)
animation_start_time = time.time() animation_start_time = time.time()
@ -882,7 +890,7 @@ class LightHuePlugin(LightPlugin):
lights = _next_light_attrs(lights) lights = _next_light_attrs(lights)
self.logger.info('Stopping animation') get_bus().post(LightAnimationStoppedEvent(lights=lights, groups=groups, animation=animation))
self.animation_thread = None self.animation_thread = None
self.animation_thread = Thread(target=_animate_thread, self.animation_thread = Thread(target=_animate_thread,