forked from platypush/platypush
Added switch tab to the new web panel
This commit is contained in:
parent
26ee3fc75c
commit
b932df1c12
8 changed files with 299 additions and 95 deletions
|
@ -0,0 +1,36 @@
|
||||||
|
@import 'common/vars';
|
||||||
|
|
||||||
|
$head-bg: #e8e8e8;
|
||||||
|
|
||||||
|
.switches-root {
|
||||||
|
.switch-root {
|
||||||
|
.head {
|
||||||
|
padding: 1rem .5rem;
|
||||||
|
background: $head-bg;
|
||||||
|
border-top: $default-border-2;
|
||||||
|
border-bottom: $default-border-2;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switches {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 2rem;
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(odd) { background: rgba(255, 255, 255, 0.0); }
|
||||||
|
&:nth-child(even) { background: $default-bg-3; }
|
||||||
|
&:hover { background: $hover-bg; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
99
platypush/backend/http/static/js/plugins/switches/index.js
Normal file
99
platypush/backend/http/static/js/plugins/switches/index.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
const SwitchDevice = Vue.component('switch-device', {
|
||||||
|
template: '#tmpl-switch-device',
|
||||||
|
props: {
|
||||||
|
bus: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
device: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const SwitchType = Vue.component('switch-type', {
|
||||||
|
template: '#tmpl-switch-type',
|
||||||
|
props: {
|
||||||
|
bus: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
devices: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('switches', {
|
||||||
|
template: '#tmpl-switches',
|
||||||
|
props: ['config'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
bus: new Vue({}),
|
||||||
|
plugins: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
refresh: async function() {
|
||||||
|
if (!this.config.plugins) {
|
||||||
|
console.warn('Please specify a list of switch plugins in your switch section configuration');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const promises = this.config.plugins.map(plugin => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request(plugin + '.status').then(status => {
|
||||||
|
const ret = {};
|
||||||
|
ret[plugin] = status;
|
||||||
|
resolve(ret);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const statuses = (await Promise.all(promises)).reduce((obj, status) => {
|
||||||
|
obj[Object.keys(status)[0]] = Object.values(status)[0].reduce((obj2, device) => {
|
||||||
|
device.type = Object.keys(status)[0];
|
||||||
|
obj2[device.id] = device;
|
||||||
|
return obj2;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
for (const [name, status] of Object.entries(statuses)) {
|
||||||
|
this.plugins[name] = status;
|
||||||
|
|
||||||
|
const switchType = new SwitchType();
|
||||||
|
switchType.bus = this.bus;
|
||||||
|
switchType.name = name;
|
||||||
|
switchType.devices = this.plugins[name];
|
||||||
|
|
||||||
|
switchType.$mount();
|
||||||
|
this.$refs.root.appendChild(switchType.$el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle: async function(type, device) {
|
||||||
|
let status = await request(type + '.toggle', {device: device});
|
||||||
|
this.plugins[type][status.id].on = status.on;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function() {
|
||||||
|
const self = this;
|
||||||
|
this.refresh();
|
||||||
|
|
||||||
|
this.bus.$on('switch-toggled', (evt) => {
|
||||||
|
self.toggle(evt.type, evt.device);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
'media.vlc': 'fa fa-film',
|
'media.vlc': 'fa fa-film',
|
||||||
'music.mpd': 'fa fa-music',
|
'music.mpd': 'fa fa-music',
|
||||||
'music.snapcast': 'fa fa-volume-up',
|
'music.snapcast': 'fa fa-volume-up',
|
||||||
|
'switches': 'fa fa-toggle-on',
|
||||||
'tts': 'fa fa-comment',
|
'tts': 'fa fa-comment',
|
||||||
'tts.google': 'fa fa-comment',
|
'tts.google': 'fa fa-comment',
|
||||||
}
|
}
|
||||||
|
@ -20,7 +21,7 @@
|
||||||
{% if plugin in pluginIcons %}
|
{% if plugin in pluginIcons %}
|
||||||
<i class="{{ pluginIcons[plugin] }}"></i>
|
<i class="{{ pluginIcons[plugin] }}"></i>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% raw %}{{ plugin }}{{% endraw %}
|
{{ plugin }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
27
platypush/backend/http/templates/plugins/switches/index.html
Normal file
27
platypush/backend/http/templates/plugins/switches/index.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<script type="text/x-template" id="tmpl-switches">
|
||||||
|
<div class="switches-root" ref="root"></div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="tmpl-switch-type">
|
||||||
|
<div class="switch-root" ref="root">
|
||||||
|
<div class="head" v-text="name.split('.').pop()"></div>
|
||||||
|
|
||||||
|
<div class="switches">
|
||||||
|
<switch-device :device="device"
|
||||||
|
v-for="device in devices"
|
||||||
|
:key="device.name"
|
||||||
|
:bus="bus">
|
||||||
|
</switch-device>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="tmpl-switch-device">
|
||||||
|
<div class="device">
|
||||||
|
<div class="col-10 name" v-text="device.name"></div>
|
||||||
|
<div class="col-2 toggle">
|
||||||
|
<toggle-switch :value="device.on" @toggled="bus.$emit('switch-toggled', {type: device.type, device: device.id})"></toggle-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
|
@ -1,33 +1,45 @@
|
||||||
from platypush.plugins import Plugin, action
|
from platypush.plugins import Plugin, action
|
||||||
|
|
||||||
|
|
||||||
class SwitchPlugin(Plugin):
|
class SwitchPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
Abstract class for interacting with switch devices
|
Abstract class for interacting with switch devices
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def on(self, args):
|
def on(self, device, *args, **kwargs):
|
||||||
""" Turn the device on """
|
""" Turn the device on """
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def off(self, args):
|
def off(self, device, *args, **kwargs):
|
||||||
""" Turn the device off """
|
""" Turn the device off """
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def toggle(self, args):
|
def toggle(self, device, *args, **kwargs):
|
||||||
""" Toggle the device status (on/off) """
|
""" Toggle the device status (on/off) """
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def status(self):
|
def status(self, device=None, *args, **kwargs):
|
||||||
""" Get the device state """
|
""" Get the status of a specified device or of all the configured devices (default)"""
|
||||||
|
devices = self.devices
|
||||||
|
if device:
|
||||||
|
devices = [d for d in self.devices if d.get('id') == device or d.get('name') == device]
|
||||||
|
if devices:
|
||||||
|
return self.devices.pop(0)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return devices
|
||||||
|
|
||||||
|
@property
|
||||||
|
def devices(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
||||||
|
|
|
@ -7,48 +7,52 @@ from bluetooth.ble import DiscoveryService, GATTRequester
|
||||||
from platypush.plugins import action
|
from platypush.plugins import action
|
||||||
from platypush.plugins.switch import SwitchPlugin
|
from platypush.plugins.switch import SwitchPlugin
|
||||||
|
|
||||||
|
|
||||||
class Scanner(object):
|
class Scanner(object):
|
||||||
|
"""
|
||||||
|
XXX The Scanner object doesn't work. Add your devices by address statically to the plugin configuration for now
|
||||||
|
instead of relying on scanning capabilities
|
||||||
|
"""
|
||||||
|
|
||||||
service_uuid = '1bc5d5a5-0200b89f-e6114d22-000da2cb'
|
service_uuid = '1bc5d5a5-0200b89f-e6114d22-000da2cb'
|
||||||
|
|
||||||
def __init__(self, bt_interface=None, timeout_secs=None):
|
def __init__(self, bt_interface=None, timeout_secs=None):
|
||||||
self.bt_interface = bt_interface
|
self.bt_interface = bt_interface
|
||||||
self.timeout_secs = timeout_secs if timeout_secs else 2
|
self.timeout_secs = timeout_secs if timeout_secs else 2
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_uuids(cls, device):
|
def _get_uuids(cls, device):
|
||||||
uuids = set()
|
uuids = set()
|
||||||
|
|
||||||
for id in device['uuids']:
|
for uuid in device['uuids']:
|
||||||
if isinstance(id, tuple):
|
if isinstance(uuid, tuple):
|
||||||
uuid = ''
|
uuid = ''
|
||||||
for i in range(0, len(id)):
|
for i in range(0, len(uuid)):
|
||||||
token = struct.pack('<I', id[i])
|
token = struct.pack('<I', uuid[i])
|
||||||
for byte in token:
|
for byte in token:
|
||||||
uuid += hex(byte)[2:].zfill(2)
|
uuid += hex(byte)[2:].zfill(2)
|
||||||
uuid += ('-' if i < len(id)-1 else '')
|
uuid += ('-' if i < len(uuid)-1 else '')
|
||||||
uuids.add(uuid)
|
uuids.add(uuid)
|
||||||
else:
|
else:
|
||||||
uuids.add(hex(id)[2:])
|
uuids.add(hex(uuid)[2:])
|
||||||
|
|
||||||
return uuids
|
return uuids
|
||||||
|
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
service = DiscoveryService(self.bt_interface) \
|
service = DiscoveryService(self.bt_interface) \
|
||||||
if self.bt_interface else DiscoveryService()
|
if self.bt_interface else DiscoveryService()
|
||||||
|
|
||||||
devices = service.discover(self.timeout_secs)
|
devices = service.discover(self.timeout_secs)
|
||||||
return sorted([addr for addr, device in devices.items()
|
return sorted([addr for addr, device in devices.items()
|
||||||
if self.service_uuid in self._get_uuids(device)])
|
if self.service_uuid in self._get_uuids(device)])
|
||||||
|
|
||||||
|
|
||||||
class Driver(object):
|
class Driver(object):
|
||||||
handle = 0x16
|
handle = 0x16
|
||||||
commands = {
|
commands = {
|
||||||
'press' : '\x57\x01\x00',
|
'press': '\x57\x01\x00',
|
||||||
'on' : '\x57\x01\x01',
|
'on': '\x57\x01\x01',
|
||||||
'off' : '\x57\x01\x02',
|
'off': '\x57\x01\x02',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, device, bt_interface=None, timeout_secs=None):
|
def __init__(self, device, bt_interface=None, timeout_secs=None):
|
||||||
|
@ -57,7 +61,6 @@ class Driver(object):
|
||||||
self.timeout_secs = timeout_secs if timeout_secs else 5
|
self.timeout_secs = timeout_secs if timeout_secs else 5
|
||||||
self.req = None
|
self.req = None
|
||||||
|
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
if self.bt_interface:
|
if self.bt_interface:
|
||||||
self.req = GATTRequester(self.device, False, self.bt_interface)
|
self.req = GATTRequester(self.device, False, self.bt_interface)
|
||||||
|
@ -66,6 +69,7 @@ class Driver(object):
|
||||||
|
|
||||||
self.req.connect(True, 'random')
|
self.req.connect(True, 'random')
|
||||||
connect_start_time = time.time()
|
connect_start_time = time.time()
|
||||||
|
|
||||||
while not self.req.is_connected():
|
while not self.req.is_connected():
|
||||||
if time.time() - connect_start_time >= self.timeout_secs:
|
if time.time() - connect_start_time >= self.timeout_secs:
|
||||||
raise RuntimeError('Connection to {} timed out after {} seconds'
|
raise RuntimeError('Connection to {} timed out after {} seconds'
|
||||||
|
@ -96,7 +100,7 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bt_interface=None, connect_timeout=None,
|
def __init__(self, bt_interface=None, connect_timeout=None,
|
||||||
scan_timeout=None, devices={}, *args, **kwargs):
|
scan_timeout=None, devices=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param bt_interface: Bluetooth interface to use (e.g. hci0) default: first available one
|
:param bt_interface: Bluetooth interface to use (e.g. hci0) default: first available one
|
||||||
:type bt_interface: str
|
:type bt_interface: str
|
||||||
|
@ -111,20 +115,30 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
:type devices: dict
|
:type devices: dict
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
if devices is None:
|
||||||
|
devices = {}
|
||||||
|
|
||||||
self.bt_interface = bt_interface
|
self.bt_interface = bt_interface
|
||||||
self.connect_timeout = connect_timeout if connect_timeout else 5
|
self.connect_timeout = connect_timeout if connect_timeout else 5
|
||||||
self.scan_timeout = scan_timeout if scan_timeout else 2
|
self.scan_timeout = scan_timeout if scan_timeout else 2
|
||||||
self.devices = devices
|
self.configured_devices = devices
|
||||||
|
self.configured_devices_by_name = {
|
||||||
|
name: addr
|
||||||
|
for addr, name in self.configured_devices.items()
|
||||||
|
}
|
||||||
|
|
||||||
def _run(self, device, command=None):
|
def _run(self, device, command=None):
|
||||||
|
if device in self.configured_devices_by_name:
|
||||||
|
device = self.configured_devices_by_name[device]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# XXX this requires sudo and it's executed in its own process
|
# XXX this requires sudo and it's executed in its own process
|
||||||
# because the Switchbot plugin requires root privileges to send
|
# because the Switchbot plugin requires root privileges to send
|
||||||
# raw bluetooth messages on the interface. Make sure that the user
|
# raw bluetooth messages on the interface. Make sure that the user
|
||||||
# that runs platypush has the right permissions to run this with sudo
|
# that runs platypush has the right permissions to run this with sudo
|
||||||
return subprocess.check_output((
|
output = subprocess.check_output((
|
||||||
'sudo python3 -m platypush.plugins.switch.switchbot ' +
|
'sudo python3 -m platypush.plugins.switch.switchbot ' +
|
||||||
'--device {} ' +
|
'--device {} ' +
|
||||||
('--interface {} '.format(self.bt_interface) if self.bt_interface else '') +
|
('--interface {} '.format(self.bt_interface) if self.bt_interface else '') +
|
||||||
|
@ -134,6 +148,8 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise RuntimeError(e.output.decode('utf-8'))
|
raise RuntimeError(e.output.decode('utf-8'))
|
||||||
|
|
||||||
|
self.logger.info('Output of switchbot command: {}'.format(output))
|
||||||
|
return self.status(device)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def press(self, device):
|
def press(self, device):
|
||||||
|
@ -146,7 +162,11 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
return self._run(device)
|
return self._run(device)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def on(self, device):
|
def toggle(self, device, **kwargs):
|
||||||
|
return self.press(device)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def on(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Send a press-on button command to a device
|
Send a press-on button command to a device
|
||||||
|
|
||||||
|
@ -156,7 +176,7 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
return self._run(device, 'on')
|
return self._run(device, 'on')
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def off(self, device):
|
def off(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Send a press-off button command to a device
|
Send a press-off button command to a device
|
||||||
|
|
||||||
|
@ -167,7 +187,11 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def scan(self):
|
def scan(self):
|
||||||
""" Scan for available Switchbot devices nearby """
|
"""
|
||||||
|
Scan for available Switchbot devices nearby.
|
||||||
|
XXX This action doesn't work for now. Configure your devices statically for now instead of
|
||||||
|
relying on the scanner
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return subprocess.check_output(
|
return subprocess.check_output(
|
||||||
'sudo python3 -m platypush.plugins.switch.switchbot --scan ' +
|
'sudo python3 -m platypush.plugins.switch.switchbot --scan ' +
|
||||||
|
@ -177,6 +201,17 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise RuntimeError(e.output.decode('utf-8'))
|
raise RuntimeError(e.output.decode('utf-8'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def devices(self):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'address': addr,
|
||||||
|
'id': addr,
|
||||||
|
'name': name,
|
||||||
|
'on': False,
|
||||||
|
}
|
||||||
|
for addr, name in self.configured_devices.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,14 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
||||||
_ip_to_dev = {}
|
_ip_to_dev = {}
|
||||||
_alias_to_dev = {}
|
_alias_to_dev = {}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
def _scan(self):
|
def _scan(self):
|
||||||
devices = Discover.discover()
|
devices = Discover.discover()
|
||||||
self._ip_to_dev = {}
|
self._ip_to_dev = {}
|
||||||
self._alias_to_dev = {}
|
self._alias_to_dev = {}
|
||||||
|
|
||||||
|
|
||||||
for (ip, dev) in devices.items():
|
for (ip, dev) in devices.items():
|
||||||
self._ip_to_dev[ip] = dev
|
self._ip_to_dev[ip] = dev
|
||||||
self._alias_to_dev[dev.alias] = dev
|
self._alias_to_dev[dev.alias] = dev
|
||||||
|
@ -47,27 +46,8 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Device {} not found'.format(device))
|
raise RuntimeError('Device {} not found'.format(device))
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def status(self):
|
def on(self, device, **kwargs):
|
||||||
"""
|
|
||||||
:returns: The available device over the network as a
|
|
||||||
"""
|
|
||||||
|
|
||||||
devices = { 'devices': {
|
|
||||||
ip: {
|
|
||||||
'alias': dev.alias,
|
|
||||||
'current_consumption': dev.current_consumption(),
|
|
||||||
'host': dev.host,
|
|
||||||
'hw_info': dev.hw_info,
|
|
||||||
'on': dev.is_on,
|
|
||||||
} for (ip, dev) in self._scan().items()
|
|
||||||
} }
|
|
||||||
|
|
||||||
return devices
|
|
||||||
|
|
||||||
@action
|
|
||||||
def on(self, device):
|
|
||||||
"""
|
"""
|
||||||
Turn on a device
|
Turn on a device
|
||||||
|
|
||||||
|
@ -77,11 +57,10 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
||||||
|
|
||||||
device = self._get_device(device)
|
device = self._get_device(device)
|
||||||
device.turn_on()
|
device.turn_on()
|
||||||
return {'status':'on'}
|
return self.status(device)
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def off(self, device):
|
def off(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Turn off a device
|
Turn off a device
|
||||||
|
|
||||||
|
@ -91,11 +70,10 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
||||||
|
|
||||||
device = self._get_device(device)
|
device = self._get_device(device)
|
||||||
device.turn_off()
|
device.turn_off()
|
||||||
return {'status':'off'}
|
return self.status(device)
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def toggle(self, device):
|
def toggle(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Toggle the state of a device (on/off)
|
Toggle the state of a device (on/off)
|
||||||
|
|
||||||
|
@ -103,15 +81,36 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
||||||
:type device: str
|
:type device: str
|
||||||
"""
|
"""
|
||||||
|
|
||||||
device = self._get_device(device, use_cache=False)
|
device = self._get_device(device)
|
||||||
|
|
||||||
if device.is_on:
|
if device.is_on:
|
||||||
device.turn_off()
|
device.turn_off()
|
||||||
else:
|
else:
|
||||||
device.turn_on()
|
device.turn_on()
|
||||||
|
|
||||||
return {'status': 'off' if device.is_off else 'on'}
|
return {
|
||||||
|
'current_consumption': device.current_consumption(),
|
||||||
|
'id': device.host,
|
||||||
|
'ip': device.host,
|
||||||
|
'host': device.host,
|
||||||
|
'hw_info': device.hw_info,
|
||||||
|
'name': device.alias,
|
||||||
|
'on': device.is_on,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def devices(self):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'current_consumption': dev.current_consumption(),
|
||||||
|
'id': ip,
|
||||||
|
'ip': ip,
|
||||||
|
'host': dev.host,
|
||||||
|
'hw_info': dev.hw_info,
|
||||||
|
'name': dev.alias,
|
||||||
|
'on': dev.is_on,
|
||||||
|
} for (ip, dev) in self._scan().items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import json
|
|
||||||
|
|
||||||
from platypush.plugins import action
|
from platypush.plugins import action
|
||||||
from platypush.plugins.switch import SwitchPlugin
|
from platypush.plugins.switch import SwitchPlugin
|
||||||
|
|
||||||
|
|
||||||
class SwitchWemoPlugin(SwitchPlugin):
|
class SwitchWemoPlugin(SwitchPlugin):
|
||||||
"""
|
"""
|
||||||
Plugin to control a Belkin WeMo smart switch
|
Plugin to control a Belkin WeMo smart switches
|
||||||
(https://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/)
|
(https://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/)
|
||||||
|
|
||||||
Requires:
|
Requires:
|
||||||
|
@ -14,13 +12,13 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
* **ouimeaux** (``pip install ouimeaux``)
|
* **ouimeaux** (``pip install ouimeaux``)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, discovery_seconds=3, *args, **kwargs):
|
def __init__(self, discovery_seconds=3, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param discovery_seconds: Discovery time when scanning for devices (default: 3)
|
:param discovery_seconds: Discovery time when scanning for devices (default: 3)
|
||||||
:type discovery_seconds: int
|
:type discovery_seconds: int
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(**kwargs)
|
||||||
self.discovery_seconds = discovery_seconds
|
self.discovery_seconds = discovery_seconds
|
||||||
self.env = None
|
self.env = None
|
||||||
|
|
||||||
|
@ -29,7 +27,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
self.logger.info('Starting WeMo discovery')
|
self.logger.info('Starting WeMo discovery')
|
||||||
self._get_environment()
|
self._get_environment()
|
||||||
self.env.discover(seconds=self.discovery_seconds)
|
self.env.discover(seconds=self.discovery_seconds)
|
||||||
self.devices = self.env.devices
|
self._devices = self.env.devices
|
||||||
|
|
||||||
def _get_environment(self):
|
def _get_environment(self):
|
||||||
if not self.env:
|
if not self.env:
|
||||||
|
@ -38,18 +36,17 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
self.env.start()
|
self.env.start()
|
||||||
self._refresh_devices()
|
self._refresh_devices()
|
||||||
|
|
||||||
@action
|
@property
|
||||||
def get_devices(self):
|
def devices(self):
|
||||||
"""
|
"""
|
||||||
Get the list of available devices
|
Get the list of available devices
|
||||||
:returns: The list of devices.
|
:returns: The list of devices.
|
||||||
|
|
||||||
Example output::
|
Example output::
|
||||||
|
|
||||||
output = {
|
output = [
|
||||||
"devices": [
|
|
||||||
{
|
{
|
||||||
"host": "192.168.1.123",
|
"ip": "192.168.1.123",
|
||||||
"name": "Switch 1",
|
"name": "Switch 1",
|
||||||
"state": 1,
|
"state": 1,
|
||||||
"model": "Belkin Plugin Socket 1.0",
|
"model": "Belkin Plugin Socket 1.0",
|
||||||
|
@ -60,40 +57,39 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
# ...
|
# ...
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
self._refresh_devices()
|
self._refresh_devices()
|
||||||
return {
|
|
||||||
'devices': [
|
return [
|
||||||
{
|
{
|
||||||
'host': dev.host,
|
'id': dev.name,
|
||||||
'name': dev.name,
|
'ip': dev.host,
|
||||||
'state': dev.get_state(),
|
'name': dev.name,
|
||||||
'model': dev.model,
|
'model': dev.model,
|
||||||
'serialnumber': dev.serialnumber,
|
'on': True if dev.get_state() else False,
|
||||||
}
|
'serialnumber': dev.serialnumber,
|
||||||
for (name, dev) in self.devices.items()
|
}
|
||||||
]
|
for (name, dev) in self._devices.items()
|
||||||
}
|
]
|
||||||
|
|
||||||
def _exec(self, method, device, *args, **kwargs):
|
def _exec(self, method, device, *args, **kwargs):
|
||||||
self._get_environment()
|
self._get_environment()
|
||||||
|
|
||||||
if device not in self.devices:
|
if device not in self._devices:
|
||||||
self._refresh_devices()
|
self._refresh_devices()
|
||||||
|
|
||||||
if device not in self.devices:
|
if device not in self._devices:
|
||||||
raise RuntimeError('Device {} not found'.format(device))
|
raise RuntimeError('Device {} not found'.format(device))
|
||||||
|
|
||||||
self.logger.info('Executing {} on WeMo device {}'.
|
self.logger.info('Executing {} on WeMo device {}'.
|
||||||
format(method, device))
|
format(method, device))
|
||||||
dev = self.devices[device]
|
dev = self._devices[device]
|
||||||
getattr(dev, method)(*args, **kwargs)
|
getattr(dev, method)(*args, **kwargs)
|
||||||
|
|
||||||
return {'device': device, 'state': dev.get_state()}
|
return self.status(device)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def on(self, device):
|
def on(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Turn a switch on
|
Turn a switch on
|
||||||
|
|
||||||
|
@ -103,7 +99,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
return self._exec('on', device)
|
return self._exec('on', device)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def off(self, device):
|
def off(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Turn a switch off
|
Turn a switch off
|
||||||
|
|
||||||
|
@ -113,7 +109,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
return self._exec('off', device)
|
return self._exec('off', device)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def toggle(self, device):
|
def toggle(self, device, **kwargs):
|
||||||
"""
|
"""
|
||||||
Toggle the state of a switch (on/off)
|
Toggle the state of a switch (on/off)
|
||||||
|
|
||||||
|
@ -124,4 +120,3 @@ class SwitchWemoPlugin(SwitchPlugin):
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue