Major LINT fixes

This commit is contained in:
Fabio Manganiello 2021-04-05 00:58:44 +02:00
parent 86761e7088
commit 2a78f81a7b
101 changed files with 527 additions and 669 deletions

View File

@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
Given the high speed of development in the first phase, changes are being reported only starting from v0.20.2. Given the high speed of development in the first phase, changes are being reported only starting from v0.20.2.
## [Unreleased]
### Fixed
- Major LINT fixes.
- Removed unmaintained integrations: TorrentCast and Booking.com
## [0.20.8] - 2021-04-04 ## [0.20.8] - 2021-04-04
### Added ### Added

View File

@ -28,7 +28,6 @@ Events
platypush/events/gps.rst platypush/events/gps.rst
platypush/events/http.rst platypush/events/http.rst
platypush/events/http.hook.rst platypush/events/http.hook.rst
platypush/events/http.ota.booking.rst
platypush/events/http.rss.rst platypush/events/http.rss.rst
platypush/events/inotify.rst platypush/events/inotify.rst
platypush/events/joystick.rst platypush/events/joystick.rst

View File

@ -1,5 +0,0 @@
``platypush.message.event.http.ota.booking``
============================================
.. automodule:: platypush.message.event.http.ota.booking
:members:

View File

@ -1,5 +0,0 @@
``platypush.plugins.http.request.ota.booking``
==============================================
.. automodule:: platypush.plugins.http.request.ota.booking
:members:

View File

@ -1,5 +0,0 @@
``platypush.plugins.video.torrentcast``
=======================================
.. automodule:: platypush.plugins.video.torrentcast
:members:

View File

@ -61,7 +61,6 @@ Plugins
platypush/plugins/graphite.rst platypush/plugins/graphite.rst
platypush/plugins/homeseer.rst platypush/plugins/homeseer.rst
platypush/plugins/http.request.rst platypush/plugins/http.request.rst
platypush/plugins/http.request.ota.booking.rst
platypush/plugins/http.request.rss.rst platypush/plugins/http.request.rss.rst
platypush/plugins/http.webpage.rst platypush/plugins/http.webpage.rst
platypush/plugins/ifttt.rst platypush/plugins/ifttt.rst
@ -137,7 +136,6 @@ Plugins
platypush/plugins/user.rst platypush/plugins/user.rst
platypush/plugins/utils.rst platypush/plugins/utils.rst
platypush/plugins/variable.rst platypush/plugins/variable.rst
platypush/plugins/video.torrentcast.rst
platypush/plugins/weather.rst platypush/plugins/weather.rst
platypush/plugins/weather.buienradar.rst platypush/plugins/weather.buienradar.rst
platypush/plugins/weather.darksky.rst platypush/plugins/weather.darksky.rst

View File

@ -6,10 +6,9 @@
import logging import logging
import re import re
import socket import socket
import threading
import time import time
from threading import Thread from threading import Thread, Event as ThreadEvent, get_ident
from typing import Optional, Dict from typing import Optional, Dict
from platypush.bus import Bus from platypush.bus import Bus
@ -62,7 +61,7 @@ class Backend(Thread, EventGenerator):
self.poll_seconds = float(poll_seconds) if poll_seconds else None self.poll_seconds = float(poll_seconds) if poll_seconds else None
self.device_id = Config.get('device_id') self.device_id = Config.get('device_id')
self.thread_id = None self.thread_id = None
self._stop_event = threading.Event() self._stop_event = ThreadEvent()
self._kwargs = kwargs self._kwargs = kwargs
self.logger = logging.getLogger('platypush:backend:' + get_backend_name_by_class(self.__class__)) self.logger = logging.getLogger('platypush:backend:' + get_backend_name_by_class(self.__class__))
self.zeroconf = None self.zeroconf = None
@ -220,7 +219,7 @@ class Backend(Thread, EventGenerator):
def run(self): def run(self):
""" Starts the backend thread. To be implemented in the derived classes if the loop method isn't defined. """ """ Starts the backend thread. To be implemented in the derived classes if the loop method isn't defined. """
self.thread_id = threading.get_ident() self.thread_id = get_ident()
set_thread_name(self._thread_name) set_thread_name(self._thread_name)
if not callable(self.loop): if not callable(self.loop):
return return

View File

@ -65,11 +65,11 @@ class AdafruitIoBackend(Backend):
def on_message(self, msg): def on_message(self, msg):
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def _handler(client, feed, data): def _handler(client, feed, data):
# noinspection PyBroadException
try: try:
data = float(data) data = float(data)
except: except Exception as e:
pass self.logger.debug('Not a number: {}: {}'.format(data, e))
self.bus.post(FeedUpdateEvent(feed=feed, data=data)) self.bus.post(FeedUpdateEvent(feed=feed, data=data))
return _handler return _handler

View File

@ -55,15 +55,17 @@ class Alarm:
self._runtime_snooze_interval = snooze_interval self._runtime_snooze_interval = snooze_interval
def get_next(self) -> float: def get_next(self) -> float:
now = datetime.datetime.now().replace(tzinfo=gettz()) now = datetime.datetime.now().replace(tzinfo=gettz()) # lgtm [py/call-to-non-callable]
try: try:
cron = croniter.croniter(self.when, now) cron = croniter.croniter(self.when, now)
return cron.get_next() return cron.get_next()
except (AttributeError, croniter.CroniterBadCronError): except (AttributeError, croniter.CroniterBadCronError):
try: try:
# lgtm [py/call-to-non-callable]
timestamp = datetime.datetime.fromisoformat(self.when).replace(tzinfo=gettz()) timestamp = datetime.datetime.fromisoformat(self.when).replace(tzinfo=gettz())
except (TypeError, ValueError): except (TypeError, ValueError):
# lgtm [py/call-to-non-callable]
timestamp = (datetime.datetime.now().replace(tzinfo=gettz()) + timestamp = (datetime.datetime.now().replace(tzinfo=gettz()) +
datetime.timedelta(seconds=int(self.when))) datetime.timedelta(seconds=int(self.when)))

View File

@ -13,37 +13,41 @@ Bd addr are represented as standard python strings, e.g. "aa:bb:cc:dd:ee:ff".
import asyncio import asyncio
from enum import Enum from enum import Enum
from collections import namedtuple from collections import namedtuple
import time
import struct import struct
import itertools import itertools
class CreateConnectionChannelError(Enum): class CreateConnectionChannelError(Enum):
NoError = 0 NoError = 0
MaxPendingConnectionsReached = 1 MaxPendingConnectionsReached = 1
class ConnectionStatus(Enum): class ConnectionStatus(Enum):
Disconnected = 0 Disconnected = 0
Connected = 1 Connected = 1
Ready = 2 Ready = 2
class DisconnectReason(Enum): class DisconnectReason(Enum):
Unspecified = 0 Unspecified = 0
ConnectionEstablishmentFailed = 1 ConnectionEstablishmentFailed = 1
TimedOut = 2 TimedOut = 2
BondingKeysMismatch = 3 BondingKeysMismatch = 3
class RemovedReason(Enum): class RemovedReason(Enum):
RemovedByThisClient = 0 RemovedByThisClient = 0
ForceDisconnectedByThisClient = 1 ForceDisconnectedByThisClient = 1
ForceDisconnectedByOtherClient = 2 ForceDisconnectedByOtherClient = 2
ButtonIsPrivate = 3 ButtonIsPrivate = 3
VerifyTimeout = 4 VerifyTimeout = 4
InternetBackendError = 5 InternetBackendError = 5
InvalidData = 6 InvalidData = 6
CouldntLoadDevice = 7 CouldntLoadDevice = 7
class ClickType(Enum): class ClickType(Enum):
ButtonDown = 0 ButtonDown = 0
ButtonUp = 1 ButtonUp = 1
@ -52,20 +56,24 @@ class ClickType(Enum):
ButtonDoubleClick = 4 ButtonDoubleClick = 4
ButtonHold = 5 ButtonHold = 5
class BdAddrType(Enum): class BdAddrType(Enum):
PublicBdAddrType = 0 PublicBdAddrType = 0
RandomBdAddrType = 1 RandomBdAddrType = 1
class LatencyMode(Enum): class LatencyMode(Enum):
NormalLatency = 0 NormalLatency = 0
LowLatency = 1 LowLatency = 1
HighLatency = 2 HighLatency = 2
class BluetoothControllerState(Enum): class BluetoothControllerState(Enum):
Detached = 0 Detached = 0
Resetting = 1 Resetting = 1
Attached = 2 Attached = 2
class ScanWizardResult(Enum): class ScanWizardResult(Enum):
WizardSuccess = 0 WizardSuccess = 0
WizardCancelledByUser = 1 WizardCancelledByUser = 1
@ -75,24 +83,26 @@ class ScanWizardResult(Enum):
WizardInternetBackendError = 5 WizardInternetBackendError = 5
WizardInvalidData = 6 WizardInvalidData = 6
class ButtonScanner: class ButtonScanner:
"""ButtonScanner class. """ButtonScanner class.
Usage: Usage:
scanner = ButtonScanner() scanner = ButtonScanner()
scanner.on_advertisement_packet = lambda scanner, bd_addr, name, rssi, is_private, already_verified: ... scanner.on_advertisement_packet = lambda scanner, bd_addr, name, rssi, is_private, already_verified: ...
client.add_scanner(scanner) client.add_scanner(scanner)
""" """
_cnt = itertools.count() _cnt = itertools.count()
def __init__(self): def __init__(self):
self._scan_id = next(ButtonScanner._cnt) self._scan_id = next(ButtonScanner._cnt)
self.on_advertisement_packet = lambda scanner, bd_addr, name, rssi, is_private, already_verified: None self.on_advertisement_packet = lambda scanner, bd_addr, name, rssi, is_private, already_verified: None
class ScanWizard: class ScanWizard:
"""ScanWizard class """ScanWizard class
Usage: Usage:
wizard = ScanWizard() wizard = ScanWizard()
wizard.on_found_private_button = lambda scan_wizard: ... wizard.on_found_private_button = lambda scan_wizard: ...
@ -101,9 +111,9 @@ class ScanWizard:
wizard.on_completed = lambda scan_wizard, result, bd_addr, name: ... wizard.on_completed = lambda scan_wizard, result, bd_addr, name: ...
client.add_scan_wizard(wizard) client.add_scan_wizard(wizard)
""" """
_cnt = itertools.count() _cnt = itertools.count()
def __init__(self): def __init__(self):
self._scan_wizard_id = next(ScanWizard._cnt) self._scan_wizard_id = next(ScanWizard._cnt)
self._bd_addr = None self._bd_addr = None
@ -113,33 +123,34 @@ class ScanWizard:
self.on_button_connected = lambda scan_wizard, bd_addr, name: None self.on_button_connected = lambda scan_wizard, bd_addr, name: None
self.on_completed = lambda scan_wizard, result, bd_addr, name: None self.on_completed = lambda scan_wizard, result, bd_addr, name: None
class ButtonConnectionChannel: class ButtonConnectionChannel:
"""ButtonConnectionChannel class. """ButtonConnectionChannel class.
This class represents a connection channel to a Flic button. This class represents a connection channel to a Flic button.
Add this button connection channel to a FlicClient by executing client.add_connection_channel(connection_channel). Add this button connection channel to a FlicClient by executing client.add_connection_channel(connection_channel).
You may only have this connection channel added to one FlicClient at a time. You may only have this connection channel added to one FlicClient at a time.
Before you add the connection channel to the client, you should set up your callback functions by assigning Before you add the connection channel to the client, you should set up your callback functions by assigning
the corresponding properties to this object with a function. Each callback function has a channel parameter as the first one, the corresponding properties to this object with a function. Each callback function has a channel parameter as the first one,
referencing this object. referencing this object.
Available properties and the function parameters are: Available properties and the function parameters are:
on_create_connection_channel_response: channel, error, connection_status on_create_connection_channel_response: channel, error, connection_status
on_removed: channel, removed_reason on_removed: channel, removed_reason
on_connection_status_changed: channel, connection_status, disconnect_reason on_connection_status_changed: channel, connection_status, disconnect_reason
on_button_up_or_down / on_button_click_or_hold / on_button_single_or_double_click / on_button_single_or_double_click_or_hold: channel, click_type, was_queued, time_diff on_button_up_or_down / on_button_click_or_hold / on_button_single_or_double_click / on_button_single_or_double_click_or_hold: channel, click_type, was_queued, time_diff
""" """
_cnt = itertools.count() _cnt = itertools.count()
def __init__(self, bd_addr, latency_mode = LatencyMode.NormalLatency, auto_disconnect_time = 511): def __init__(self, bd_addr, latency_mode=LatencyMode.NormalLatency, auto_disconnect_time=511):
self._conn_id = next(ButtonConnectionChannel._cnt) self._conn_id = next(ButtonConnectionChannel._cnt)
self._bd_addr = bd_addr self._bd_addr = bd_addr
self._latency_mode = latency_mode self._latency_mode = latency_mode
self._auto_disconnect_time = auto_disconnect_time self._auto_disconnect_time = auto_disconnect_time
self._client = None self._client = None
self.on_create_connection_channel_response = lambda channel, error, connection_status: None self.on_create_connection_channel_response = lambda channel, error, connection_status: None
self.on_removed = lambda channel, removed_reason: None self.on_removed = lambda channel, removed_reason: None
self.on_connection_status_changed = lambda channel, connection_status, disconnect_reason: None self.on_connection_status_changed = lambda channel, connection_status, disconnect_reason: None
@ -147,61 +158,66 @@ class ButtonConnectionChannel:
self.on_button_click_or_hold = lambda channel, click_type, was_queued, time_diff: None self.on_button_click_or_hold = lambda channel, click_type, was_queued, time_diff: None
self.on_button_single_or_double_click = lambda channel, click_type, was_queued, time_diff: None self.on_button_single_or_double_click = lambda channel, click_type, was_queued, time_diff: None
self.on_button_single_or_double_click_or_hold = lambda channel, click_type, was_queued, time_diff: None self.on_button_single_or_double_click_or_hold = lambda channel, click_type, was_queued, time_diff: None
@property @property
def bd_addr(self): def bd_addr(self):
return self._bd_addr return self._bd_addr
@property @property
def latency_mode(self): def latency_mode(self):
return self._latency_mode return self._latency_mode
@latency_mode.setter @latency_mode.setter
def latency_mode(self, latency_mode): def latency_mode(self, latency_mode):
if self._client is None: if self._client is None:
self._latency_mode = latency_mode self._latency_mode = latency_mode
return return
self._latency_mode = latency_mode self._latency_mode = latency_mode
if not self._client._closed: if not self._client._closed:
self._client._send_command("CmdChangeModeParameters", {"conn_id": self._conn_id, "latency_mode": self._latency_mode, "auto_disconnect_time": self._auto_disconnect_time}) self._client._send_command("CmdChangeModeParameters",
{"conn_id": self._conn_id, "latency_mode": self._latency_mode,
"auto_disconnect_time": self._auto_disconnect_time})
@property @property
def auto_disconnect_time(self): def auto_disconnect_time(self):
return self._auto_disconnect_time return self._auto_disconnect_time
@auto_disconnect_time.setter @auto_disconnect_time.setter
def auto_disconnect_time(self, auto_disconnect_time): def auto_disconnect_time(self, auto_disconnect_time):
if self._client is None: if self._client is None:
self._auto_disconnect_time = auto_disconnect_time self._auto_disconnect_time = auto_disconnect_time
return return
self._auto_disconnect_time = auto_disconnect_time self._auto_disconnect_time = auto_disconnect_time
if not self._client._closed: if not self._client._closed:
self._client._send_command("CmdChangeModeParameters", {"conn_id": self._conn_id, "latency_mode": self._latency_mode, "auto_disconnect_time": self._auto_disconnect_time}) self._client._send_command("CmdChangeModeParameters",
{"conn_id": self._conn_id, "latency_mode": self._latency_mode,
"auto_disconnect_time": self._auto_disconnect_time})
class FlicClient(asyncio.Protocol): class FlicClient(asyncio.Protocol):
"""FlicClient class. """FlicClient class.
When this class is constructed, a socket connection is established. When this class is constructed, a socket connection is established.
You may then send commands to the server and set timers. You may then send commands to the server and set timers.
Once you are ready with the initialization you must call the handle_events() method which is a main loop that never exits, unless the socket is closed. Once you are ready with the initialization you must call the handle_events() method which is a main loop that never exits, unless the socket is closed.
For a more detailed description of all commands, events and enums, check the protocol specification. For a more detailed description of all commands, events and enums, check the protocol specification.
All commands are wrapped in more high level functions and events are reported using callback functions. All commands are wrapped in more high level functions and events are reported using callback functions.
All methods called on this class will take effect only if you eventually call the handle_events() method. All methods called on this class will take effect only if you eventually call the handle_events() method.
The ButtonScanner is used to set up a handler for advertisement packets. The ButtonScanner is used to set up a handler for advertisement packets.
The ButtonConnectionChannel is used to interact with connections to flic buttons and receive their events. The ButtonConnectionChannel is used to interact with connections to flic buttons and receive their events.
Other events are handled by the following callback functions that can be assigned to this object (and a list of the callback function parameters): Other events are handled by the following callback functions that can be assigned to this object (and a list of the callback function parameters):
on_new_verified_button: bd_addr on_new_verified_button: bd_addr
on_no_space_for_new_connection: max_concurrently_connected_buttons on_no_space_for_new_connection: max_concurrently_connected_buttons
on_got_space_for_new_connection: max_concurrently_connected_buttons on_got_space_for_new_connection: max_concurrently_connected_buttons
on_bluetooth_controller_state_change: state on_bluetooth_controller_state_change: state
""" """
_EVENTS = [ _EVENTS = [
("EvtAdvertisementPacket", "<I6s17pb??", "scan_id bd_addr name rssi is_private already_verified"), ("EvtAdvertisementPacket", "<I6s17pb??", "scan_id bd_addr name rssi is_private already_verified"),
("EvtCreateConnectionChannelResponse", "<IBB", "conn_id error connection_status"), ("EvtCreateConnectionChannelResponse", "<IBB", "conn_id error connection_status"),
@ -212,7 +228,8 @@ class FlicClient(asyncio.Protocol):
("EvtButtonSingleOrDoubleClick", "<IBBI", "conn_id click_type was_queued time_diff"), ("EvtButtonSingleOrDoubleClick", "<IBBI", "conn_id click_type was_queued time_diff"),
("EvtButtonSingleOrDoubleClickOrHold", "<IBBI", "conn_id click_type was_queued time_diff"), ("EvtButtonSingleOrDoubleClickOrHold", "<IBBI", "conn_id click_type was_queued time_diff"),
("EvtNewVerifiedButton", "<6s", "bd_addr"), ("EvtNewVerifiedButton", "<6s", "bd_addr"),
("EvtGetInfoResponse", "<B6sBBhBBH", "bluetooth_controller_state my_bd_addr my_bd_addr_type max_pending_connections max_concurrently_connected_buttons current_pending_connections currently_no_space_for_new_connection nb_verified_buttons"), ("EvtGetInfoResponse", "<B6sBBhBBH",
"bluetooth_controller_state my_bd_addr my_bd_addr_type max_pending_connections max_concurrently_connected_buttons current_pending_connections currently_no_space_for_new_connection nb_verified_buttons"),
("EvtNoSpaceForNewConnection", "<B", "max_concurrently_connected_buttons"), ("EvtNoSpaceForNewConnection", "<B", "max_concurrently_connected_buttons"),
("EvtGotSpaceForNewConnection", "<B", "max_concurrently_connected_buttons"), ("EvtGotSpaceForNewConnection", "<B", "max_concurrently_connected_buttons"),
("EvtBluetoothControllerStateChange", "<B", "state"), ("EvtBluetoothControllerStateChange", "<B", "state"),
@ -223,9 +240,9 @@ class FlicClient(asyncio.Protocol):
("EvtScanWizardButtonConnected", "<I", "scan_wizard_id"), ("EvtScanWizardButtonConnected", "<I", "scan_wizard_id"),
("EvtScanWizardCompleted", "<IB", "scan_wizard_id result") ("EvtScanWizardCompleted", "<IB", "scan_wizard_id result")
] ]
_EVENT_STRUCTS = list(map(lambda x: None if x == None else struct.Struct(x[1]), _EVENTS)) _EVENT_STRUCTS = list(map(lambda x: None if x is None else struct.Struct(x[1]), _EVENTS))
_EVENT_NAMED_TUPLES = list(map(lambda x: None if x == None else namedtuple(x[0], x[2]), _EVENTS)) _EVENT_NAMED_TUPLES = list(map(lambda x: None if x is None else namedtuple(x[0], x[2]), _EVENTS))
_COMMANDS = [ _COMMANDS = [
("CmdGetInfo", "", ""), ("CmdGetInfo", "", ""),
("CmdCreateScanner", "<I", "scan_id"), ("CmdCreateScanner", "<I", "scan_id"),
@ -239,168 +256,169 @@ class FlicClient(asyncio.Protocol):
("CmdCreateScanWizard", "<I", "scan_wizard_id"), ("CmdCreateScanWizard", "<I", "scan_wizard_id"),
("CmdCancelScanWizard", "<I", "scan_wizard_id") ("CmdCancelScanWizard", "<I", "scan_wizard_id")
] ]
_COMMAND_STRUCTS = list(map(lambda x: struct.Struct(x[1]), _COMMANDS)) _COMMAND_STRUCTS = list(map(lambda x: struct.Struct(x[1]), _COMMANDS))
_COMMAND_NAMED_TUPLES = list(map(lambda x: namedtuple(x[0], x[2]), _COMMANDS)) _COMMAND_NAMED_TUPLES = list(map(lambda x: namedtuple(x[0], x[2]), _COMMANDS))
_COMMAND_NAME_TO_OPCODE = dict((x[0], i) for i, x in enumerate(_COMMANDS)) _COMMAND_NAME_TO_OPCODE = dict((x[0], i) for i, x in enumerate(_COMMANDS))
@staticmethod
def _bdaddr_bytes_to_string(bdaddr_bytes): def _bdaddr_bytes_to_string(bdaddr_bytes):
return ":".join(map(lambda x: "%02x" % x, reversed(bdaddr_bytes))) return ":".join(map(lambda x: "%02x" % x, reversed(bdaddr_bytes)))
@staticmethod
def _bdaddr_string_to_bytes(bdaddr_string): def _bdaddr_string_to_bytes(bdaddr_string):
return bytearray.fromhex("".join(reversed(bdaddr_string.split(":")))) return bytearray.fromhex("".join(reversed(bdaddr_string.split(":"))))
def __init__(self, loop,parent=None): def __init__(self, loop, parent=None):
self.loop = loop self.loop = loop
self.buffer=b"" self.buffer = b""
self.transport=None self.transport = None
self.parent=parent self.parent = parent
self._scanners = {} self._scanners = {}
self._scan_wizards = {} self._scan_wizards = {}
self._connection_channels = {} self._connection_channels = {}
self._closed = False self._closed = False
self.on_new_verified_button = lambda bd_addr: None self.on_new_verified_button = lambda bd_addr: None
self.on_no_space_for_new_connection = lambda max_concurrently_connected_buttons: None self.on_no_space_for_new_connection = lambda max_concurrently_connected_buttons: None
self.on_got_space_for_new_connection = lambda max_concurrently_connected_buttons: None self.on_got_space_for_new_connection = lambda max_concurrently_connected_buttons: None
self.on_bluetooth_controller_state_change = lambda state: None self.on_bluetooth_controller_state_change = lambda state: None
self.on_get_info = lambda items: None self.on_get_info = lambda items: None
self.on_get_button_uuid = lambda addr, uuid: None self.on_get_button_uuid = lambda addr, uuid: None
def connection_made(self, transport): def connection_made(self, transport):
self.transport=transport self.transport = transport
if self.parent: if self.parent:
self.parent.register_protocol(self) self.parent.register_protocol(self)
def close(self): def close(self):
"""Closes the client. The handle_events() method will return.""" """Closes the client. The handle_events() method will return."""
if self._closed: if self._closed:
return return
self._closed = True self._closed = True
def add_scanner(self, scanner): def add_scanner(self, scanner):
"""Add a ButtonScanner object. """Add a ButtonScanner object.
The scan will start directly once the scanner is added. The scan will start directly once the scanner is added.
""" """
if scanner._scan_id in self._scanners: if scanner._scan_id in self._scanners:
return return
self._scanners[scanner._scan_id] = scanner self._scanners[scanner._scan_id] = scanner
self._send_command("CmdCreateScanner", {"scan_id": scanner._scan_id}) self._send_command("CmdCreateScanner", {"scan_id": scanner._scan_id})
def remove_scanner(self, scanner): def remove_scanner(self, scanner):
"""Remove a ButtonScanner object. """Remove a ButtonScanner object.
You will no longer receive advertisement packets. You will no longer receive advertisement packets.
""" """
if scanner._scan_id not in self._scanners: if scanner._scan_id not in self._scanners:
return return
del self._scanners[scanner._scan_id] del self._scanners[scanner._scan_id]
self._send_command("CmdRemoveScanner", {"scan_id": scanner._scan_id}) self._send_command("CmdRemoveScanner", {"scan_id": scanner._scan_id})
def add_scan_wizard(self, scan_wizard): def add_scan_wizard(self, scan_wizard):
"""Add a ScanWizard object. """Add a ScanWizard object.
The scan wizard will start directly once the scan wizard is added. The scan wizard will start directly once the scan wizard is added.
""" """
if scan_wizard._scan_wizard_id in self._scan_wizards: if scan_wizard._scan_wizard_id in self._scan_wizards:
return return
self._scan_wizards[scan_wizard._scan_wizard_id] = scan_wizard self._scan_wizards[scan_wizard._scan_wizard_id] = scan_wizard
self._send_command("CmdCreateScanWizard", {"scan_wizard_id": scan_wizard._scan_wizard_id}) self._send_command("CmdCreateScanWizard", {"scan_wizard_id": scan_wizard._scan_wizard_id})
def cancel_scan_wizard(self, scan_wizard): def cancel_scan_wizard(self, scan_wizard):
"""Cancel a ScanWizard. """Cancel a ScanWizard.
Note: The effect of this command will take place at the time the on_completed event arrives on the scan wizard object. Note: The effect of this command will take place at the time the on_completed event arrives on the scan wizard object.
If cancelled due to this command, "result" in the on_completed event will be "WizardCancelledByUser". If cancelled due to this command, "result" in the on_completed event will be "WizardCancelledByUser".
""" """
if scan_wizard._scan_wizard_id not in self._scan_wizards: if scan_wizard._scan_wizard_id not in self._scan_wizards:
return return
self._send_command("CmdCancelScanWizard", {"scan_wizard_id": scan_wizard._scan_wizard_id}) self._send_command("CmdCancelScanWizard", {"scan_wizard_id": scan_wizard._scan_wizard_id})
def add_connection_channel(self, channel): def add_connection_channel(self, channel):
"""Adds a connection channel to a specific Flic button. """Adds a connection channel to a specific Flic button.
This will start listening for a specific Flic button's connection and button events. This will start listening for a specific Flic button's connection and button events.
Make sure the Flic is either in public mode (by holding it down for 7 seconds) or already verified before calling this method. Make sure the Flic is either in public mode (by holding it down for 7 seconds) or already verified before calling this method.
The on_create_connection_channel_response callback property will be called on the The on_create_connection_channel_response callback property will be called on the
connection channel after this command has been received by the server. connection channel after this command has been received by the server.
You may have as many connection channels as you wish for a specific Flic Button. You may have as many connection channels as you wish for a specific Flic Button.
""" """
if channel._conn_id in self._connection_channels: if channel._conn_id in self._connection_channels:
return return
channel._client = self channel._client = self
self._connection_channels[channel._conn_id] = channel self._connection_channels[channel._conn_id] = channel
self._send_command("CmdCreateConnectionChannel", {"conn_id": channel._conn_id, "bd_addr": channel.bd_addr, "latency_mode": channel._latency_mode, "auto_disconnect_time": channel._auto_disconnect_time}) self._send_command("CmdCreateConnectionChannel", {"conn_id": channel._conn_id, "bd_addr": channel.bd_addr,
"latency_mode": channel._latency_mode,
"auto_disconnect_time": channel._auto_disconnect_time})
def remove_connection_channel(self, channel): def remove_connection_channel(self, channel):
"""Remove a connection channel. """Remove a connection channel.
This will stop listening for new events for a specific connection channel that has previously been added. This will stop listening for new events for a specific connection channel that has previously been added.
Note: The effect of this command will take place at the time the on_removed event arrives on the connection channel object. Note: The effect of this command will take place at the time the on_removed event arrives on the connection channel object.
""" """
if channel._conn_id not in self._connection_channels: if channel._conn_id not in self._connection_channels:
return return
self._send_command("CmdRemoveConnectionChannel", {"conn_id": channel._conn_id}) self._send_command("CmdRemoveConnectionChannel", {"conn_id": channel._conn_id})
def force_disconnect(self, bd_addr): def force_disconnect(self, bd_addr):
"""Force disconnection or cancel pending connection of a specific Flic button. """Force disconnection or cancel pending connection of a specific Flic button.
This removes all connection channels for all clients connected to the server for this specific Flic button. This removes all connection channels for all clients connected to the server for this specific Flic button.
""" """
self._send_command("CmdForceDisconnect", {"bd_addr": bd_addr}) self._send_command("CmdForceDisconnect", {"bd_addr": bd_addr})
def get_info(self): def get_info(self):
"""Get info about the current state of the server. """Get info about the current state of the server.
The server will send back its information directly and the callback will be called once the response arrives. The server will send back its information directly and the callback will be called once the response arrives.
The callback takes only one parameter: info. This info parameter is a dictionary with the following objects: The callback takes only one parameter: info. This info parameter is a dictionary with the following objects:
bluetooth_controller_state, my_bd_addr, my_bd_addr_type, max_pending_connections, max_concurrently_connected_buttons, bluetooth_controller_state, my_bd_addr, my_bd_addr_type, max_pending_connections, max_concurrently_connected_buttons,
current_pending_connections, currently_no_space_for_new_connection, bd_addr_of_verified_buttons (a list of bd addresses). current_pending_connections, currently_no_space_for_new_connection, bd_addr_of_verified_buttons (a list of bd addresses).
""" """
self._send_command("CmdGetInfo", {}) self._send_command("CmdGetInfo", {})
def get_button_uuid(self, bd_addr): def get_button_uuid(self, bd_addr):
"""Get button uuid for a verified button. """Get button uuid for a verified button.
The server will send back its information directly and the callback will be called once the response arrives. The server will send back its information directly and the callback will be called once the response arrives.
Responses will arrive in the same order as requested. Responses will arrive in the same order as requested.
The callback takes two parameters: bd_addr, uuid (hex string of 32 characters). The callback takes two parameters: bd_addr, uuid (hex string of 32 characters).
Note: if the button isn't verified, the uuid sent to the callback will rather be None. Note: if the button isn't verified, the uuid sent to the callback will rather be None.
""" """
self._send_command("CmdGetButtonUUID", {"bd_addr": bd_addr}) self._send_command("CmdGetButtonUUID", {"bd_addr": bd_addr})
def run_on_handle_events_thread(self, callback): def run_on_handle_events_thread(self, callback):
"""Run a function on the thread that handles the events.""" """Run a function on the thread that handles the events."""
if threading.get_ident() == self._handle_event_thread_ident: if threading.get_ident() == self._handle_event_thread_ident:
callback() callback()
else: else:
self.set_timer(0, callback) self.set_timer(0, callback)
def _send_command(self, name, items): def _send_command(self, name, items):
for key, value in items.items(): for key, value in items.items():
if isinstance(value, Enum): if isinstance(value, Enum):
items[key] = value.value items[key] = value.value
if "bd_addr" in items: if "bd_addr" in items:
items["bd_addr"] = FlicClient._bdaddr_string_to_bytes(items["bd_addr"]) items["bd_addr"] = FlicClient._bdaddr_string_to_bytes()
opcode = FlicClient._COMMAND_NAME_TO_OPCODE[name] opcode = FlicClient._COMMAND_NAME_TO_OPCODE[name]
data_bytes = FlicClient._COMMAND_STRUCTS[opcode].pack(*FlicClient._COMMAND_NAMED_TUPLES[opcode](**items)) data_bytes = FlicClient._COMMAND_STRUCTS[opcode].pack(*FlicClient._COMMAND_NAMED_TUPLES[opcode](**items))
bytes = bytearray(3) bytes = bytearray(3)
@ -409,83 +427,85 @@ class FlicClient(asyncio.Protocol):
bytes[2] = opcode bytes[2] = opcode
bytes += data_bytes bytes += data_bytes
self.transport.write(bytes) self.transport.write(bytes)
def _dispatch_event(self, data): def _dispatch_event(self, data):
if len(data) == 0: if len(data) == 0:
return return
opcode = data[0] opcode = data[0]
if opcode >= len(FlicClient._EVENTS) or FlicClient._EVENTS[opcode] == None: if opcode >= len(FlicClient._EVENTS) or FlicClient._EVENTS[opcode] is None:
return return
event_name = FlicClient._EVENTS[opcode][0] event_name = FlicClient._EVENTS[opcode][0]
data_tuple = FlicClient._EVENT_STRUCTS[opcode].unpack(data[1 : 1 + FlicClient._EVENT_STRUCTS[opcode].size]) data_tuple = FlicClient._EVENT_STRUCTS[opcode].unpack(data[1: 1 + FlicClient._EVENT_STRUCTS[opcode].size])
items = FlicClient._EVENT_NAMED_TUPLES[opcode]._make(data_tuple)._asdict() items = FlicClient._EVENT_NAMED_TUPLES[opcode]._make(data_tuple)._asdict()
# Process some kind of items whose data type is not supported by struct # Process some kind of items whose data type is not supported by struct
if "bd_addr" in items: if "bd_addr" in items:
items["bd_addr"] = FlicClient._bdaddr_bytes_to_string(items["bd_addr"]) items["bd_addr"] = FlicClient._bdaddr_bytes_to_string()
if "name" in items: if "name" in items:
items["name"] = items["name"].decode("utf-8") items["name"] = items["name"].decode("utf-8")
if event_name == "EvtCreateConnectionChannelResponse": if event_name == "EvtCreateConnectionChannelResponse":
items["error"] = CreateConnectionChannelError(items["error"]) items["error"] = CreateConnectionChannelError(items["error"])
items["connection_status"] = ConnectionStatus(items["connection_status"]) items["connection_status"] = ConnectionStatus(items["connection_status"])
if event_name == "EvtConnectionStatusChanged": if event_name == "EvtConnectionStatusChanged":
items["connection_status"] = ConnectionStatus(items["connection_status"]) items["connection_status"] = ConnectionStatus(items["connection_status"])
items["disconnect_reason"] = DisconnectReason(items["disconnect_reason"]) items["disconnect_reason"] = DisconnectReason(items["disconnect_reason"])
if event_name == "EvtConnectionChannelRemoved": if event_name == "EvtConnectionChannelRemoved":
items["removed_reason"] = RemovedReason(items["removed_reason"]) items["removed_reason"] = RemovedReason(items["removed_reason"])
if event_name.startswith("EvtButton"): if event_name.startswith("EvtButton"):
items["click_type"] = ClickType(items["click_type"]) items["click_type"] = ClickType(items["click_type"])
if event_name == "EvtGetInfoResponse": if event_name == "EvtGetInfoResponse":
items["bluetooth_controller_state"] = BluetoothControllerState(items["bluetooth_controller_state"]) items["bluetooth_controller_state"] = BluetoothControllerState(items["bluetooth_controller_state"])
items["my_bd_addr"] = FlicClient._bdaddr_bytes_to_string(items["my_bd_addr"]) items["my_bd_addr"] = FlicClient._bdaddr_bytes_to_string()
items["my_bd_addr_type"] = BdAddrType(items["my_bd_addr_type"]) items["my_bd_addr_type"] = BdAddrType(items["my_bd_addr_type"])
items["bd_addr_of_verified_buttons"] = [] items["bd_addr_of_verified_buttons"] = []
pos = FlicClient._EVENT_STRUCTS[opcode].size pos = FlicClient._EVENT_STRUCTS[opcode].size
for i in range(items["nb_verified_buttons"]): for i in range(items["nb_verified_buttons"]):
items["bd_addr_of_verified_buttons"].append(FlicClient._bdaddr_bytes_to_string(data[1 + pos : 1 + pos + 6])) items["bd_addr_of_verified_buttons"].append(
FlicClient._bdaddr_bytes_to_string())
pos += 6 pos += 6
if event_name == "EvtBluetoothControllerStateChange": if event_name == "EvtBluetoothControllerStateChange":
items["state"] = BluetoothControllerState(items["state"]) items["state"] = BluetoothControllerState(items["state"])
if event_name == "EvtGetButtonUUIDResponse": if event_name == "EvtGetButtonUUIDResponse":
items["uuid"] = "".join(map(lambda x: "%02x" % x, items["uuid"])) items["uuid"] = "".join(map(lambda x: "%02x" % x, items["uuid"]))
if items["uuid"] == "00000000000000000000000000000000": if items["uuid"] == "00000000000000000000000000000000":
items["uuid"] = None items["uuid"] = None
if event_name == "EvtScanWizardCompleted": if event_name == "EvtScanWizardCompleted":
items["result"] = ScanWizardResult(items["result"]) items["result"] = ScanWizardResult(items["result"])
# Process event # Process event
if event_name == "EvtAdvertisementPacket": if event_name == "EvtAdvertisementPacket":
scanner = self._scanners.get(items["scan_id"]) scanner = self._scanners.get(items["scan_id"])
if scanner is not None: if scanner is not None:
scanner.on_advertisement_packet(scanner, items["bd_addr"], items["name"], items["rssi"], items["is_private"], items["already_verified"]) scanner.on_advertisement_packet(scanner, items["bd_addr"], items["name"], items["rssi"],
items["is_private"], items["already_verified"])
if event_name == "EvtCreateConnectionChannelResponse": if event_name == "EvtCreateConnectionChannelResponse":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
if items["error"] != CreateConnectionChannelError.NoError: if items["error"] != CreateConnectionChannelError.NoError:
del self._connection_channels[items["conn_id"]] del self._connection_channels[items["conn_id"]]
channel.on_create_connection_channel_response(channel, items["error"], items["connection_status"]) channel.on_create_connection_channel_response(channel, items["error"], items["connection_status"])
if event_name == "EvtConnectionStatusChanged": if event_name == "EvtConnectionStatusChanged":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
channel.on_connection_status_changed(channel, items["connection_status"], items["disconnect_reason"]) channel.on_connection_status_changed(channel, items["connection_status"], items["disconnect_reason"])
if event_name == "EvtConnectionChannelRemoved": if event_name == "EvtConnectionChannelRemoved":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
del self._connection_channels[items["conn_id"]] del self._connection_channels[items["conn_id"]]
channel.on_removed(channel, items["removed_reason"]) channel.on_removed(channel, items["removed_reason"])
if event_name == "EvtButtonUpOrDown": if event_name == "EvtButtonUpOrDown":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
channel.on_button_up_or_down(channel, items["click_type"], items["was_queued"], items["time_diff"]) channel.on_button_up_or_down(channel, items["click_type"], items["was_queued"], items["time_diff"])
@ -494,61 +514,60 @@ class FlicClient(asyncio.Protocol):
channel.on_button_click_or_hold(channel, items["click_type"], items["was_queued"], items["time_diff"]) channel.on_button_click_or_hold(channel, items["click_type"], items["was_queued"], items["time_diff"])
if event_name == "EvtButtonSingleOrDoubleClick": if event_name == "EvtButtonSingleOrDoubleClick":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
channel.on_button_single_or_double_click(channel, items["click_type"], items["was_queued"], items["time_diff"]) channel.on_button_single_or_double_click(channel, items["click_type"], items["was_queued"],
items["time_diff"])
if event_name == "EvtButtonSingleOrDoubleClickOrHold": if event_name == "EvtButtonSingleOrDoubleClickOrHold":
channel = self._connection_channels[items["conn_id"]] channel = self._connection_channels[items["conn_id"]]
channel.on_button_single_or_double_click_or_hold(channel, items["click_type"], items["was_queued"], items["time_diff"]) channel.on_button_single_or_double_click_or_hold(channel, items["click_type"], items["was_queued"],
items["time_diff"])
if event_name == "EvtNewVerifiedButton": if event_name == "EvtNewVerifiedButton":
self.on_new_verified_button(items["bd_addr"]) self.on_new_verified_button(items["bd_addr"])
if event_name == "EvtGetInfoResponse": if event_name == "EvtGetInfoResponse":
self.on_get_info(items) self.on_get_info(items)
if event_name == "EvtNoSpaceForNewConnection": if event_name == "EvtNoSpaceForNewConnection":
self.on_no_space_for_new_connection(items["max_concurrently_connected_buttons"]) self.on_no_space_for_new_connection(items["max_concurrently_connected_buttons"])
if event_name == "EvtGotSpaceForNewConnection": if event_name == "EvtGotSpaceForNewConnection":
self.on_got_space_for_new_connection(items["max_concurrently_connected_buttons"]) self.on_got_space_for_new_connection(items["max_concurrently_connected_buttons"])
if event_name == "EvtBluetoothControllerStateChange": if event_name == "EvtBluetoothControllerStateChange":
self.on_bluetooth_controller_state_change(items["state"]) self.on_bluetooth_controller_state_change(items["state"])
if event_name == "EvtGetButtonUUIDResponse": if event_name == "EvtGetButtonUUIDResponse":
self.on_get_button_uuid(items["bd_addr"], items["uuid"]) self.on_get_button_uuid(items["bd_addr"], items["uuid"])
if event_name == "EvtScanWizardFoundPrivateButton": if event_name == "EvtScanWizardFoundPrivateButton":
scan_wizard = self._scan_wizards[items["scan_wizard_id"]] scan_wizard = self._scan_wizards[items["scan_wizard_id"]]
scan_wizard.on_found_private_button(scan_wizard) scan_wizard.on_found_private_button(scan_wizard)
if event_name == "EvtScanWizardFoundPublicButton": if event_name == "EvtScanWizardFoundPublicButton":
scan_wizard = self._scan_wizards[items["scan_wizard_id"]] scan_wizard = self._scan_wizards[items["scan_wizard_id"]]
scan_wizard._bd_addr = items["bd_addr"] scan_wizard._bd_addr = items["bd_addr"]
scan_wizard._name = items["name"] scan_wizard._name = items["name"]
scan_wizard.on_found_public_button(scan_wizard, scan_wizard._bd_addr, scan_wizard._name) scan_wizard.on_found_public_button(scan_wizard, scan_wizard._bd_addr, scan_wizard._name)
if event_name == "EvtScanWizardButtonConnected": if event_name == "EvtScanWizardButtonConnected":
scan_wizard = self._scan_wizards[items["scan_wizard_id"]] scan_wizard = self._scan_wizards[items["scan_wizard_id"]]
scan_wizard.on_button_connected(scan_wizard, scan_wizard._bd_addr, scan_wizard._name) scan_wizard.on_button_connected(scan_wizard, scan_wizard._bd_addr, scan_wizard._name)
if event_name == "EvtScanWizardCompleted": if event_name == "EvtScanWizardCompleted":
scan_wizard = self._scan_wizards[items["scan_wizard_id"]] scan_wizard = self._scan_wizards[items["scan_wizard_id"]]
del self._scan_wizards[items["scan_wizard_id"]] del self._scan_wizards[items["scan_wizard_id"]]
scan_wizard.on_completed(scan_wizard, items["result"], scan_wizard._bd_addr, scan_wizard._name) scan_wizard.on_completed(scan_wizard, items["result"], scan_wizard._bd_addr, scan_wizard._name)
def data_received(self, data):
def data_received(self,data): cdata = self.buffer + data
cdata=self.buffer+data self.buffer = b""
self.buffer=b""
while len(cdata): while len(cdata):
packet_len = cdata[0] | (cdata[1] << 8) packet_len = cdata[0] | (cdata[1] << 8)
packet_len += 2 packet_len += 2
if len(cdata)>= packet_len: if len(cdata) >= packet_len:
self._dispatch_event(cdata[2:packet_len]) self._dispatch_event(cdata[2:packet_len])
cdata=cdata[packet_len:] cdata = cdata[packet_len:]
else: else:
if len(cdata): if len(cdata):
self.buffer=cdata #unlikely to happen but..... self.buffer = cdata # unlikely to happen but.....
break break

View File

@ -34,7 +34,7 @@ class CameraPiBackend(Backend):
return self.value == other return self.value == other
# noinspection PyUnresolvedReferences,PyPackageRequirements # noinspection PyUnresolvedReferences,PyPackageRequirements
def __init__(self, listen_port, x_resolution=640, y_resolution=480, def __init__(self, listen_port, bind_address='0.0.0.0', x_resolution=640, y_resolution=480,
redis_queue='platypush/camera/pi', redis_queue='platypush/camera/pi',
start_recording_on_startup=True, start_recording_on_startup=True,
framerate=24, hflip=False, vflip=False, framerate=24, hflip=False, vflip=False,
@ -49,13 +49,17 @@ class CameraPiBackend(Backend):
:param listen_port: Port where the camera process will provide the video output while recording :param listen_port: Port where the camera process will provide the video output while recording
:type listen_port: int :type listen_port: int
:param bind_address: Bind address (default: 0.0.0.0).
:type bind_address: str
""" """
super().__init__(**kwargs) super().__init__(**kwargs)
self.bind_address = bind_address
self.listen_port = listen_port self.listen_port = listen_port
self.server_socket = socket.socket() self.server_socket = socket.socket()
self.server_socket.bind(('0.0.0.0', self.listen_port)) self.server_socket.bind((self.bind_address, self.listen_port))
self.server_socket.listen(0) self.server_socket.listen(0)
import picamera import picamera
@ -134,13 +138,13 @@ class CameraPiBackend(Backend):
self.logger.info('Client closed connection') self.logger.info('Client closed connection')
try: try:
self.stop_recording() self.stop_recording()
except: except Exception as e:
pass self.logger.warning('Could not stop recording: {}'.format(str(e)))
try: try:
connection.close() connection.close()
except: except Exception as e:
pass self.logger.warning('Could not close connection: {}'.format(str(e)))
self.send_camera_action(self.CameraAction.START_RECORDING) self.send_camera_action(self.CameraAction.START_RECORDING)

View File

@ -51,11 +51,10 @@ class GooglePubsubBackend(Backend):
def _message_callback(self, topic): def _message_callback(self, topic):
def callback(msg): def callback(msg):
data = msg.data.decode() data = msg.data.decode()
# noinspection PyBroadException
try: try:
data = json.loads(data) data = json.loads(data)
except: except Exception as e:
pass self.logger.debug('Not a valid JSON: {}: {}'.format(data, str(e)))
msg.ack() msg.ack()
self.bus.post(GooglePubsubMessageEvent(topic=topic, msg=data)) self.bus.post(GooglePubsubMessageEvent(topic=topic, msg=data))

View File

@ -31,8 +31,8 @@ def _hook(hook_name):
# noinspection PyBroadException # noinspection PyBroadException
try: try:
event_args['data'] = json.loads(event_args['data']) event_args['data'] = json.loads(event_args['data'])
except: except Exception as e:
pass logger().warning('Not a valid JSON string: {}: {}'.format(event_args['data'], str(e)))
event = WebhookEvent(**event_args) event = WebhookEvent(**event_args)

View File

@ -31,7 +31,7 @@ def login():
if session_token: if session_token:
user, session = user_manager.authenticate_user_session(session_token) user, session = user_manager.authenticate_user_session(session_token)
if user: if user:
return redirect(redirect_page, 302) return redirect(redirect_page, 302) # lgtm [py/url-redirection]
if request.form: if request.form:
username = request.form.get('username') username = request.form.get('username')
@ -44,7 +44,7 @@ def login():
expires_at=expires) expires_at=expires)
if session: if session:
redirect_target = redirect(redirect_page, 302) redirect_target = redirect(redirect_page, 302) # lgtm [py/url-redirection]
response = make_response(redirect_target) response = make_response(redirect_target)
response.set_cookie('session_token', session.session_token, expires=expires) response.set_cookie('session_token', session.session_token, expires=expires)
return response return response

View File

@ -25,7 +25,7 @@ def logout():
if not user: if not user:
return abort(403, 'Invalid session token') return abort(403, 'Invalid session token')
redirect_target = redirect(redirect_page, 302) redirect_target = redirect(redirect_page, 302) # lgtm [py/url-redirection]
response = make_response(redirect_target) response = make_response(redirect_target)
response.set_cookie('session_token', '', expires=0) response.set_cookie('session_token', '', expires=0)
return response return response

View File

@ -32,8 +32,8 @@ def add_media():
args = {} args = {}
try: try:
args = json.loads(request.data.decode('utf-8')) args = json.loads(request.data.decode('utf-8'))
except: except Exception as e:
abort(400, 'Invalid JSON request') abort(400, 'Invalid JSON request: {}'.format(str(e)))
source = args.get('source') source = args.get('source')
if not source: if not source:

View File

@ -40,7 +40,7 @@ def audio_feed(device, fifo, sample_rate, blocksize, latency, channels):
channels=channels) channels=channels)
try: try:
with open(fifo, 'rb') as f: with open(fifo, 'rb') as f: # lgtm [py/path-injection]
send_header = True send_header = True
while True: while True:

View File

@ -31,10 +31,10 @@ def register():
if session_token: if session_token:
user, session = user_manager.authenticate_user_session(session_token) user, session = user_manager.authenticate_user_session(session_token)
if user: if user:
return redirect(redirect_page, 302) return redirect(redirect_page, 302) # lgtm [py/url-redirection]
if user_manager.get_user_count() > 0: if user_manager.get_user_count() > 0:
return redirect('/login?redirect=' + redirect_page, 302) return redirect('/login?redirect=' + redirect_page, 302) # lgtm [py/url-redirection]
if request.form: if request.form:
username = request.form.get('username') username = request.form.get('username')
@ -49,7 +49,7 @@ def register():
if not remember else None) if not remember else None)
if session: if session:
redirect_target = redirect(redirect_page, 302) redirect_target = redirect(redirect_page, 302) # lgtm [py/url-redirection]
response = make_response(redirect_target) response = make_response(redirect_target)
response.set_cookie('session_token', session.session_token) response.set_cookie('session_token', session.session_token)
return response return response

View File

@ -123,7 +123,8 @@ def _authenticate_token():
try: try:
user_manager.validate_jwt_token(user_token) user_manager.validate_jwt_token(user_token)
return True return True
except: except Exception as e:
logger().debug(str(e))
return token and user_token == token return token and user_token == token

View File

@ -78,11 +78,11 @@ class HttpRequest(object):
def get_new_items(self, response): def get_new_items(self, response):
""" Gets new items out of a response """ """ Gets new items out of a response """
raise ("get_new_items must be implemented in a derived class") raise NotImplementedError("get_new_items must be implemented in a derived class")
def __iter__(self): def __iter__(self):
for (key, value) in self.request_args.items(): for (key, value) in self.request_args.items():
yield (key, value) yield key, value
class JsonHttpRequest(HttpRequest): class JsonHttpRequest(HttpRequest):
@ -96,7 +96,7 @@ class JsonHttpRequest(HttpRequest):
new_entries = [] new_entries = []
if self.path: if self.path:
m = re.match('\$\{\s*(.*)\s*\}', self.path) m = re.match(r'\${\s*(.*)\s*}', self.path)
response = eval(m.group(1)) response = eval(m.group(1))
for entry in response: for entry in response:

View File

@ -238,15 +238,15 @@ class RssUpdates(HttpRequest):
with open(digest_filename, 'w', encoding='utf-8') as f: with open(digest_filename, 'w', encoding='utf-8') as f:
f.write(content) f.write(content)
elif self.digest_format == 'pdf': elif self.digest_format == 'pdf':
import weasyprint from weasyprint import HTML, CSS
from weasyprint.fonts import FontConfiguration from weasyprint.fonts import FontConfiguration
body_style = 'body { {body_style} }'.format(body_style=self.body_style) body_style = 'body { ' + self.body_style + ' }'
font_config = FontConfiguration() font_config = FontConfiguration()
css = [weasyprint.CSS('https://fonts.googleapis.com/css?family=Merriweather'), css = [CSS('https://fonts.googleapis.com/css?family=Merriweather'),
weasyprint.CSS(string=body_style, font_config=font_config)] CSS(string=body_style, font_config=font_config)]
weasyprint.HTML(string=content).write_pdf(digest_filename, stylesheets=css) HTML(string=content).write_pdf(digest_filename, stylesheets=css)
else: else:
raise RuntimeError('Unsupported format: {}. Supported formats: ' + raise RuntimeError('Unsupported format: {}. Supported formats: ' +
'html or pdf'.format(self.digest_format)) 'html or pdf'.format(self.digest_format))

View File

@ -50,15 +50,13 @@ class HttpUtils(object):
for name, resource_path in resource_dirs.items(): for name, resource_path in resource_dirs.items():
resource_path = os.path.abspath(os.path.expanduser(resource_path)) resource_path = os.path.abspath(os.path.expanduser(resource_path))
if directory.startswith(resource_path): if directory.startswith(resource_path):
subdir = re.sub('^{}(.*)$'.format(resource_path),
'\\1', directory)
uri = '/resources/' + name uri = '/resources/' + name
break break
if not uri: if not uri:
raise RuntimeError(('Directory {} not found among the available ' + raise RuntimeError(('Directory {} not found among the available ' +
'static resources on the webserver').format( 'static resources on the webserver').format(
directory)) directory))
results = [ results = [
re.sub('^{}(.*)$'.format(resource_path), uri + '\\1', path) re.sub('^{}(.*)$'.format(resource_path), uri + '\\1', path)
@ -92,10 +90,11 @@ class HttpUtils(object):
@classmethod @classmethod
def plugin_name_to_tag(cls, module_name): def plugin_name_to_tag(cls, module_name):
return module_name.replace('.','-') return module_name.replace('.', '-')
@classmethod @classmethod
def find_templates_in_dir(cls, directory): def find_templates_in_dir(cls, directory):
# noinspection PyTypeChecker
return [ return [
os.path.join(directory, file) os.path.join(directory, file)
for root, path, files in os.walk(os.path.abspath(os.path.join(template_folder, directory))) for root, path, files in os.walk(os.path.abspath(os.path.join(template_folder, directory)))

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

@ -380,20 +380,16 @@ export default {
this.request(this.action.name, args).then(this.onResponse).catch(this.onError).finally(this.onDone) this.request(this.action.name, args).then(this.onResponse).catch(this.onError).finally(this.onDone)
} else { } else {
let request = this.rawRequest
try { try {
request = JSON.parse(this.rawRequest) const request = JSON.parse(this.rawRequest)
this.execute(request).then(this.onResponse).catch(this.onError).finally(this.onDone)
} catch (e) { } catch (e) {
this.notify({ this.notify({
error: true, error: true,
title: 'Invalid JSON request', title: 'Invalid JSON request',
text: e.toString(), text: e.toString(),
}) })
return
} }
this.execute(request).then(this.onResponse).catch(this.onError).finally(this.onDone)
} }
}, },

View File

@ -110,6 +110,7 @@ export class ColorConverter {
if (isNaN(blue)) if (isNaN(blue))
blue = 0; blue = 0;
// lgtm [js/automatic-semicolon-insertion]
return [red, green, blue].map((c) => Math.min(Math.max(0, c), 255)) return [red, green, blue].map((c) => Math.min(Math.max(0, c), 255))
} }

View File

@ -454,9 +454,10 @@ export default {
brightness: hsl[2], brightness: hsl[2],
color: { color: {
hue: hsl[0], hue: hsl[0],
'`${satAttr}': hsl[1],
} }
} }
request.value.color[satAttr] = hsl[1]
} }
} }
break break

View File

@ -35,6 +35,7 @@ class KafkaBackend(Backend):
self.topic_prefix = topic self.topic_prefix = topic
self.topic = self._topic_by_device_id(self.device_id) self.topic = self._topic_by_device_id(self.device_id)
self.producer = None self.producer = None
self.consumer = None
# Kafka can be veryyyy noisy # Kafka can be veryyyy noisy
logging.getLogger('kafka').setLevel(logging.ERROR) logging.getLogger('kafka').setLevel(logging.ERROR)
@ -47,8 +48,8 @@ class KafkaBackend(Backend):
try: try:
msg = Message.build(msg) msg = Message.build(msg)
is_platypush_message = True is_platypush_message = True
except: except Exception as e:
pass self.logger.debug(str(e))
self.logger.info('Received message on Kafka backend: {}'.format(msg)) self.logger.info('Received message on Kafka backend: {}'.format(msg))
@ -60,7 +61,7 @@ class KafkaBackend(Backend):
def _topic_by_device_id(self, device_id): def _topic_by_device_id(self, device_id):
return '{}.{}'.format(self.topic_prefix, device_id) return '{}.{}'.format(self.topic_prefix, device_id)
def send_message(self, msg): def send_message(self, msg, **kwargs):
target = msg.target target = msg.target
kafka_plugin = get_plugin('kafka') kafka_plugin = get_plugin('kafka')
kafka_plugin.send_message(msg=msg, kafka_plugin.send_message(msg=msg,

View File

@ -108,8 +108,8 @@ class LogEventHandler(EventHandler):
url = m.group(5).split(' ')[1] url = m.group(5).split(' ')[1]
method = m.group(5).split(' ')[0] method = m.group(5).split(' ')[0]
http_version = m.group(5).split(' ')[2].split('/')[1] http_version = m.group(5).split(' ')[2].split('/')[1]
except: except Exception as e:
pass logger.debug(str(e))
if not url: if not url:
return return

View File

@ -275,8 +275,8 @@ class MqttBackend(Backend):
try: try:
data = data.decode('utf-8') data = data.decode('utf-8')
data = json.loads(data) data = json.loads(data)
except: except Exception as e:
pass self.logger.debug(str(e))
# noinspection PyProtectedMember # noinspection PyProtectedMember
self.bus.post(MQTTMessageEvent(host=client._host, port=client._port, topic=msg.topic, msg=data)) self.bus.post(MQTTMessageEvent(host=client._host, port=client._port, topic=msg.topic, msg=data))
@ -303,8 +303,8 @@ class MqttBackend(Backend):
try: try:
msg = json.loads(msg) msg = json.loads(msg)
msg = Message.build(msg) msg = Message.build(msg)
except: except Exception as e:
pass self.logger.debug(str(e))
if not msg: if not msg:
return return

View File

@ -49,10 +49,10 @@ class PushbulletBackend(Backend):
from pushbullet import Pushbullet from pushbullet import Pushbullet
self.pb = Pushbullet(self.token) self.pb = Pushbullet(self.token)
# noinspection PyBroadException
try: try:
self.device = self.pb.get_device(self.device_name) self.device = self.pb.get_device(self.device_name)
except: except Exception as e:
self.logger.info('Device {} does not exist: {}. Creating it'.format(self.device_name, str(e)))
self.device = self.pb.new_device(self.device_name) self.device = self.pb.new_device(self.device_name)
self.pb_device_id = self.get_device_id() self.pb_device_id = self.get_device_id()

View File

@ -60,15 +60,17 @@ class RedisBackend(Backend):
msg = data[1].decode() msg = data[1].decode()
try: try:
msg = Message.build(msg) msg = Message.build(msg)
except: except Exception as e:
self.logger.debug(str(e))
try: try:
import ast import ast
msg = Message.build(ast.literal_eval(msg)) msg = Message.build(ast.literal_eval(msg))
except: except Exception as ee:
self.logger.debug(str(ee))
try: try:
msg = json.loads(msg) msg = json.loads(msg)
except Exception as e: except Exception as eee:
self.logger.exception(e) self.logger.exception(eee)
return msg return msg

View File

@ -119,12 +119,11 @@ class SensorBackend(Backend):
if self.data is None or new_data is None: if self.data is None or new_data is None:
return new_data return new_data
# noinspection PyBroadException
try: try:
# Scalar data case # Scalar data case
new_data = self._get_value(new_data) new_data = self._get_value(new_data)
return new_data if abs(new_data - self.data) >= self.tolerance else None return new_data if abs(new_data - self.data) >= self.tolerance else None
except: except (ValueError, TypeError):
# If it's not a scalar then it should be a dict # If it's not a scalar then it should be a dict
assert isinstance(new_data, dict), 'Invalid type {} received for sensor data'.format(type(new_data)) assert isinstance(new_data, dict), 'Invalid type {} received for sensor data'.format(type(new_data))

View File

@ -6,12 +6,9 @@ import re
import time import time
from platypush.backend import Backend from platypush.backend import Backend
from platypush.message import Message
from platypush.message.event.wiimote import WiimoteEvent, \ from platypush.message.event.wiimote import WiimoteEvent, \
WiimoteConnectionEvent, WiimoteDisconnectionEvent WiimoteConnectionEvent, WiimoteDisconnectionEvent
from platypush.message.request import Request
class WiimoteBackend(Backend): class WiimoteBackend(Backend):
""" """
@ -110,8 +107,8 @@ class WiimoteBackend(Backend):
try: try:
self._wiimote.close() self._wiimote.close()
except: except Exception as e:
pass self.logger.warning('Could not close Wiimote connection: {}'.format(str(e)))
self._wiimote = None self._wiimote = None
self.bus.post(WiimoteDisconnectionEvent()) self.bus.post(WiimoteDisconnectionEvent())

View File

@ -232,10 +232,9 @@ class ZigbeeMqttBackend(MqttBackend):
if not data: if not data:
return return
# noinspection PyBroadException
try: try:
data = json.loads(data) data = json.loads(data)
except: except (ValueError, TypeError):
pass pass
if topic == 'bridge/state': if topic == 'bridge/state':

View File

@ -57,7 +57,7 @@ class Cronjob(threading.Thread):
self.state = CronjobState.ERROR self.state = CronjobState.ERROR
def wait(self): def wait(self):
now = datetime.datetime.now().replace(tzinfo=gettz()) now = datetime.datetime.now().replace(tzinfo=gettz()) # lgtm [py/call-to-non-callable]
cron = croniter.croniter(self.cron_expression, now) cron = croniter.croniter(self.cron_expression, now)
next_run = cron.get_next() next_run = cron.get_next()
self._should_stop.wait(next_run - now.timestamp()) self._should_stop.wait(next_run - now.timestamp())

View File

@ -13,7 +13,7 @@ class EventGenerator(object):
logger = logging.getLogger('platypush') logger = logging.getLogger('platypush')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._event_handlers = {} # Event type => callback map self._event_handlers = {} # Event type => callback map
def fire_event(self, event): def fire_event(self, event):
""" """
@ -25,8 +25,8 @@ class EventGenerator(object):
:type event: :class:`platypush.message.event.Event` or a subclass :type event: :class:`platypush.message.event.Event` or a subclass
""" """
def hndl_thread(): def hndl_thread(handler):
hndl(event) handler(event)
from platypush.backend import Backend from platypush.backend import Backend
from platypush.context import get_bus from platypush.context import get_bus
@ -44,8 +44,7 @@ class EventGenerator(object):
handlers.update(self._event_handlers[cls]) handlers.update(self._event_handlers[cls])
for hndl in handlers: for hndl in handlers:
threading.Thread(target=hndl_thread).start() threading.Thread(target=hndl_thread, args=(hndl,)).start()
def register_handler(self, event_type, callback): def register_handler(self, event_type, callback):
""" """
@ -64,7 +63,6 @@ class EventGenerator(object):
self._event_handlers[event_type] = set() self._event_handlers[event_type] = set()
self._event_handlers[event_type].add(callback) self._event_handlers[event_type].add(callback)
def unregister_handler(self, event_type, callback): def unregister_handler(self, event_type, callback):
""" """
Unregisters a callback handler from a camera event type. Unregisters a callback handler from a camera event type.

View File

@ -61,7 +61,8 @@ class EventProcessor(object):
if hook.priority > max_priority: if hook.priority > max_priority:
priority_hooks = {hook} priority_hooks = {hook}
elif hook.priority == max_priority and max_priority > 0: max_priority = hook.priority
elif hook.priority == max_priority:
priority_hooks.add(hook) priority_hooks.add(hook)
matched_hooks.update(priority_hooks) matched_hooks.update(priority_hooks)

View File

@ -106,10 +106,9 @@ class Message(object):
if isinstance(msg, bytes) or isinstance(msg, bytearray): if isinstance(msg, bytes) or isinstance(msg, bytearray):
msg = msg.decode('utf-8') msg = msg.decode('utf-8')
if isinstance(msg, str): if isinstance(msg, str):
# noinspection PyBroadException
try: try:
msg = json.loads(msg.strip()) msg = json.loads(msg.strip())
except: except (ValueError, TypeError):
logger.warning('Invalid JSON message: {}'.format(msg)) logger.warning('Invalid JSON message: {}'.format(msg))
assert isinstance(msg, dict) assert isinstance(msg, dict)

View File

@ -1,5 +1,3 @@
import json
from platypush.message.event import Event from platypush.message.event import Event

View File

@ -119,7 +119,6 @@ class Request(Message):
return event_args return event_args
# noinspection PyBroadException
@classmethod @classmethod
def expand_value_from_context(cls, _value, **context): def expand_value_from_context(cls, _value, **context):
for (k, v) in context.items(): for (k, v) in context.items():
@ -127,7 +126,8 @@ class Request(Message):
v = json.loads(str(v)) v = json.loads(str(v))
try: try:
exec('{}={}'.format(k, v)) exec('{}={}'.format(k, v))
except: except Exception as e:
logger.debug(str(e))
if isinstance(v, str): if isinstance(v, str):
try: try:
exec('{}="{}"'.format(k, re.sub(r'(^|[^\\])"', '\1\\"', v))) exec('{}="{}"'.format(k, re.sub(r'(^|[^\\])"', '\1\\"', v)))
@ -171,7 +171,7 @@ class Request(Message):
try: try:
return json.loads(parsed_value) return json.loads(parsed_value)
except: except (ValueError, TypeError):
return parsed_value return parsed_value
def _send_response(self, response): def _send_response(self, response):

View File

@ -40,10 +40,9 @@ class RectModel(Mapping):
class ResultModel(Mapping): class ResultModel(Mapping):
def __init__(self, result: Decoded, *args, **kwargs): def __init__(self, result: Decoded, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# noinspection PyBroadException
try: try:
data = result.data.decode() data = result.data.decode()
except: except (ValueError, TypeError):
data = base64.encodebytes(result.data).decode() data = base64.encodebytes(result.data).decode()
self.data = data self.data = data

View File

@ -142,7 +142,7 @@ class AssistantGooglePushtotalkPlugin(AssistantPlugin):
) )
) )
audio_sink = audio_device = ( audio_sink = (
audio_device or audio_helpers.SoundDeviceStream( audio_device or audio_helpers.SoundDeviceStream(
sample_rate=self.audio_sample_rate, sample_rate=self.audio_sample_rate,
sample_width=self.audio_sample_width, sample_width=self.audio_sample_width,

View File

@ -1,8 +1,6 @@
import json
import requests import requests
from platypush.config import Config from platypush.config import Config
from platypush.message import Message
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@ -22,7 +20,7 @@ class AutoremotePlugin(Plugin):
_AUTOREMOTE_MESSAGE_URL = _AUTOREMOTE_BASE_URL + '/sendmessage' _AUTOREMOTE_MESSAGE_URL = _AUTOREMOTE_BASE_URL + '/sendmessage'
_AUTOREMOTE_NOTIFICATION_URL = _AUTOREMOTE_BASE_URL + '/sendnotification' _AUTOREMOTE_NOTIFICATION_URL = _AUTOREMOTE_BASE_URL + '/sendnotification'
def __init__(self, devices=None, key=None, password=None, *args, **kwargs): def __init__(self, devices=None, key=None, password=None, **kwargs):
""" """
:param devices: Set this attribute if you want to control multiple AutoRemote devices. :param devices: Set this attribute if you want to control multiple AutoRemote devices.
This will be a map in the format:: This will be a map in the format::
@ -47,7 +45,7 @@ class AutoremotePlugin(Plugin):
:type password: str :type password: str
""" """
super().__init__(*args, **kwargs) super().__init__(**kwargs)
if key: if key:
self.devices = { key: { 'key': key, 'password': password } } self.devices = { key: { 'key': key, 'password': password } }

View File

@ -404,11 +404,10 @@ class CameraPlugin(Plugin, ABC):
frame_queue.put(None) frame_queue.put(None)
self.stop_preview(camera) self.stop_preview(camera)
for output in camera.get_outputs(): for output in camera.get_outputs():
# noinspection PyBroadException
try: try:
output.close() output.close()
except: except Exception as e:
pass self.logger.warning('Could not close camera output: {}'.format(str(e)))
self.close_device(camera, wait_capture=False) self.close_device(camera, wait_capture=False)
frame_processor.join(timeout=5.0) frame_processor.join(timeout=5.0)

View File

@ -114,11 +114,10 @@ class StreamWriter(VideoWriter, ABC):
def close(self): def close(self):
self.buffer.close() self.buffer.close()
if self.sock: if self.sock:
# noinspection PyBroadException
try: try:
self.sock.close() self.sock.close()
except: except Exception as e:
pass self.logger.warning('Could not close camera resource: {}'.format(str(e)))
super().close() super().close()

View File

@ -24,12 +24,11 @@ class CvFileWriter(FileVideoWriter):
if not self.writer: if not self.writer:
return return
# noinspection PyBroadException
try: try:
if isinstance(img, ImageType): if isinstance(img, ImageType):
# noinspection PyTypeChecker # noinspection PyTypeChecker
img = np.array(img) img = np.array(img)
except: except (ValueError, TypeError):
pass pass
self.writer.write(img) self.writer.write(img)

View File

@ -78,7 +78,7 @@ class DbPlugin(Plugin):
engine = self._get_engine(engine, *args, **kwargs) engine = self._get_engine(engine, *args, **kwargs)
with engine.connect() as connection: with engine.connect() as connection:
result = connection.execute(statement) connection.execute(statement)
def _get_table(self, table, engine=None, *args, **kwargs): def _get_table(self, table, engine=None, *args, **kwargs):
if not engine: if not engine:

View File

@ -188,11 +188,10 @@ class EspPlugin(Plugin):
def on_close(self, conn: Connection): def on_close(self, conn: Connection):
def callback(ws): def callback(ws):
# noinspection PyBroadException
try: try:
ws.close() ws.close()
except: except Exception as e:
pass self.logger.warning('Could not close connection: {}'.format(str(e)))
conn.on_close() conn.on_close()
self.logger.info('Connection to {}:{} closed'.format(conn.host, conn.port)) self.logger.info('Connection to {}:{} closed'.format(conn.host, conn.port))
@ -608,7 +607,8 @@ if {miso}:
self.execute(code, **kwargs) self.execute(code, **kwargs)
@action @action
def i2c_open(self, scl: Optional[int] = None, sda: Optional[int] = None, id: int = -1, baudrate: int = 400000, **kwargs): def i2c_open(self, scl: Optional[int] = None, sda: Optional[int] = None, id: int = -1, baudrate: int = 400000,
**kwargs):
""" """
Open a connection to an I2C (or "two-wire") port. Open a connection to an I2C (or "two-wire") port.

View File

@ -150,11 +150,10 @@ class Connection:
self._echo_received.set() self._echo_received.set()
def close(self): def close(self):
# noinspection PyBroadException
try: try:
self.ws.close() self.ws.close()
except: except Exception as e:
pass self.logger.warning('Could not close connection: {}'.format(str(e)))
self.on_close() self.on_close()
@ -243,6 +242,7 @@ class Connection:
chunk = self._downloaded_chunks.get(timeout=timeout) chunk = self._downloaded_chunks.get(timeout=timeout)
except queue.Empty: except queue.Empty:
self.on_timeout('File download timed out') self.on_timeout('File download timed out')
break
if chunk is None: if chunk is None:
break break

View File

@ -19,7 +19,7 @@ class FilePlugin(Plugin):
def _to_string(cls, content): def _to_string(cls, content):
try: try:
return json.dumps(content) return json.dumps(content)
except: except (ValueError, TypeError):
return str(content) return str(content)
@action @action

View File

@ -2,9 +2,7 @@
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com> .. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
""" """
import base64
import datetime import datetime
import os
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.google import GooglePlugin from platypush.plugins.google import GooglePlugin
@ -21,7 +19,6 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(scopes=self.scopes, *args, **kwargs) super().__init__(scopes=self.scopes, *args, **kwargs)
@action @action
def get_upcoming_events(self, max_results=10): def get_upcoming_events(self, max_results=10):
""" """
@ -40,4 +37,3 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -23,12 +23,12 @@ def get_credentials(scope):
credentials_file = get_credentials_filename(*sorted(scope.split(' '))) credentials_file = get_credentials_filename(*sorted(scope.split(' ')))
if not os.path.exists(credentials_file): if not os.path.exists(credentials_file):
raise RuntimeError(('Credentials file {} not found. Generate it through:\n' + raise RuntimeError(('Credentials file {} not found. Generate it through:\n' +
'\tpython -m platypush.plugins.google.credentials "{}" ' + '\tpython -m platypush.plugins.google.credentials "{}" ' +
'<path to client_secret.json>\n' + '<path to client_secret.json>\n' +
'\t\t[--auth_host_name AUTH_HOST_NAME]\n' + '\t\t[--auth_host_name AUTH_HOST_NAME]\n' +
'\t\t[--noauth_local_webserver]\n' + '\t\t[--noauth_local_webserver]\n' +
'\t\t[--auth_host_port [AUTH_HOST_PORT [AUTH_HOST_PORT ...]]]\n' + '\t\t[--auth_host_port [AUTH_HOST_PORT [AUTH_HOST_PORT ...]]]\n' +
'\t\t[--logging_level [DEBUG,INFO,WARNING,ERROR,CRITICAL]]\n'). '\t\t[--logging_level [DEBUG,INFO,WARNING,ERROR,CRITICAL]]\n').
format(credentials_file, scope)) format(credentials_file, scope))
store = Storage(credentials_file) store = Storage(credentials_file)
@ -48,7 +48,7 @@ def generate_credentials(client_secret_path, scope):
flow.user_agent = 'Platypush' flow.user_agent = 'Platypush'
flow.access_type = 'offline' flow.access_type = 'offline'
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
credentials = tools.run_flow(flow, store, flags) tools.run_flow(flow, store, flags)
print('Storing credentials to ' + credentials_file) print('Storing credentials to ' + credentials_file)
@ -61,7 +61,7 @@ def main():
""" """
scope = sys.argv.pop(1) if len(sys.argv) > 1 \ scope = sys.argv.pop(1) if len(sys.argv) > 1 \
else input('Space separated list of OAuth scopes: ') else input('Space separated list of OAuth scopes: ')
client_secret_path = os.path.expanduser( client_secret_path = os.path.expanduser(
sys.argv.pop(1) if len(sys.argv) > 1 sys.argv.pop(1) if len(sys.argv) > 1
@ -76,6 +76,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -3,7 +3,6 @@
""" """
import base64 import base64
import httplib2
import mimetypes import mimetypes
import os import os
@ -29,7 +28,6 @@ class GoogleMailPlugin(GooglePlugin):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(scopes=self.scopes, *args, **kwargs) super().__init__(scopes=self.scopes, *args, **kwargs)
@action @action
def compose(self, sender, to, subject, body, files=None): def compose(self, sender, to, subject, body, files=None):
""" """
@ -66,9 +64,11 @@ class GoogleMailPlugin(GooglePlugin):
content_type = 'application/octet-stream' content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1) main_type, sub_type = content_type.split('/', 1)
with open(file, 'rb') as fp: content = fp.read() with open(file, 'rb') as fp:
content = fp.read()
if main_type == 'text': if main_type == 'text':
# noinspection PyUnresolvedReferences
msg = mimetypes.MIMEText(content, _subtype=sub_type) msg = mimetypes.MIMEText(content, _subtype=sub_type)
elif main_type == 'image': elif main_type == 'image':
msg = MIMEImage(content, _subtype=sub_type) msg = MIMEImage(content, _subtype=sub_type)
@ -86,13 +86,12 @@ class GoogleMailPlugin(GooglePlugin):
message.attach(msg) message.attach(msg)
service = self.get_service('gmail', 'v1') service = self.get_service('gmail', 'v1')
body = { 'raw': base64.urlsafe_b64encode(message.as_bytes()).decode() } body = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
message = (service.users().messages().send( message = (service.users().messages().send(
userId='me', body=body).execute()) userId='me', body=body).execute())
return message return message
@action @action
def get_labels(self): def get_labels(self):
""" """
@ -103,5 +102,4 @@ class GoogleMailPlugin(GooglePlugin):
labels = results.get('labels', []) labels = results.get('labels', [])
return labels return labels
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -2,7 +2,6 @@
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com> .. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
""" """
import json
import requests import requests
from platypush.plugins import action from platypush.plugins import action
@ -18,14 +17,14 @@ class GoogleMapsPlugin(GooglePlugin):
def __init__(self, api_key, *args, **kwargs): def __init__(self, api_key, *args, **kwargs):
""" """
:param api_key: Server-side API key to be used for the requests, get one at https://console.developers.google.com :param api_key: Server-side API key to be used for the requests, get one at
https://console.developers.google.com
:type api_key: str :type api_key: str
""" """
super().__init__(scopes=self.scopes, *args, **kwargs) super().__init__(scopes=self.scopes, *args, **kwargs)
self.api_key = api_key self.api_key = api_key
@action @action
def get_address_from_latlng(self, latitude, longitude): def get_address_from_latlng(self, latitude, longitude):
""" """
@ -39,7 +38,7 @@ class GoogleMapsPlugin(GooglePlugin):
""" """
response = requests.get('https://maps.googleapis.com/maps/api/geocode/json', response = requests.get('https://maps.googleapis.com/maps/api/geocode/json',
params = { params={
'latlng': '{},{}'.format(latitude, longitude), 'latlng': '{},{}'.format(latitude, longitude),
'key': self.api_key, 'key': self.api_key,
}).json() }).json()
@ -54,7 +53,7 @@ class GoogleMapsPlugin(GooglePlugin):
if 'results' in response and response['results']: if 'results' in response and response['results']:
result = response['results'][0] result = response['results'][0]
self.logger.info('Google Maps geocode response for latlng ({},{}): {}'. self.logger.info('Google Maps geocode response for latlng ({},{}): {}'.
format(latitude, longitude, result)) format(latitude, longitude, result))
address['address'] = result['formatted_address'].split(',')[0] address['address'] = result['formatted_address'].split(',')[0]
for addr_component in result['address_components']: for addr_component in result['address_components']:
@ -81,7 +80,7 @@ class GoogleMapsPlugin(GooglePlugin):
""" """
response = requests.get('https://maps.googleapis.com/maps/api/elevation/json', response = requests.get('https://maps.googleapis.com/maps/api/elevation/json',
params = { params={
'locations': '{},{}'.format(latitude, longitude), 'locations': '{},{}'.format(latitude, longitude),
'key': self.api_key, 'key': self.api_key,
}).json() }).json()
@ -91,8 +90,6 @@ class GoogleMapsPlugin(GooglePlugin):
if response.get('results'): if response.get('results'):
elevation = response['results'][0]['elevation'] elevation = response['results'][0]['elevation']
return { 'elevation': elevation } return {'elevation': elevation}
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -78,8 +78,8 @@ class GpioSensorDistanceVl53L1XPlugin(GpioSensorPlugin):
try: try:
self._device.stop_ranging() self._device.stop_ranging()
self._device.close() self._device.close()
except: except Exception as e:
pass self.logger.warning('Error while closing device: {}'.format(str(e)))
self._device = None self._device = None
time.sleep(1) time.sleep(1)

View File

@ -12,7 +12,7 @@ class MCP3008Mode(enum.Enum):
class GpioSensorMcp3008Plugin(GpioSensorPlugin): class GpioSensorMcp3008Plugin(GpioSensorPlugin):
""" """
Plugin to read analog sensor values from an MCP3008 chipset. The MCP3008 Plugin to read analog sensor values from an MCP3008 chipset. The MCP3008
chipset is a circuit that allows you to read measuremnts from multiple chipset is a circuit that allows you to read measurements from multiple
analog sources (e.g. sensors) and multiplex them to a digital device like a analog sources (e.g. sensors) and multiplex them to a digital device like a
Raspberry Pi or a regular laptop. See Raspberry Pi or a regular laptop. See
https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/mcp3008 https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/mcp3008
@ -25,8 +25,9 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
N_CHANNELS = 8 N_CHANNELS = 8
# noinspection PyPep8Naming
def __init__(self, CLK=None, MISO=None, MOSI=None, CS=None, spi_port=None, def __init__(self, CLK=None, MISO=None, MOSI=None, CS=None, spi_port=None,
spi_device=None, channels=None, Vdd=3.3, *args, **kwargs): spi_device=None, channels=None, Vdd=3.3, **kwargs):
""" """
The MCP3008 can be connected in two modes: The MCP3008 can be connected in two modes:
@ -54,8 +55,8 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
:param spi_device: (hardware SPI mode) SPI device name :param spi_device: (hardware SPI mode) SPI device name
:type spi_device: str :type spi_device: str
:param channels: name-value mapping between MCP3008 output PINs and sensor names. This mapping will be used when you get values through :func:`.get_measurement()`. :param channels: name-value mapping between MCP3008 output PINs and sensor names. This mapping will be used
Example:: when you get values through :func:`.get_measurement()`. Example::
channels = { channels = {
"0": { "0": {
@ -83,7 +84,7 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
:type Vdd: float :type Vdd: float
""" """
super().__init__(*args, **kwargs) super().__init__(**kwargs)
if CLK and MISO and MOSI and CS: if CLK and MISO and MOSI and CS:
self.CLK = CLK self.CLK = CLK
@ -154,6 +155,7 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
if i in self.channels: if i in self.channels:
channel = self.channels[i] channel = self.channels[i]
if 'conv_function' in channel: if 'conv_function' in channel:
# noinspection PyUnusedLocal
x = value x = value
value = eval(channel['conv_function']) value = eval(channel['conv_function'])

View File

@ -164,8 +164,9 @@ Warning, this new I?C address will still be used after resetting the power on th
print('Missing ZeroBorg at %02X' % oldAddress) print('Missing ZeroBorg at %02X' % oldAddress)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
foundChip = False foundChip = False
print(str(e))
print('Missing ZeroBorg at %02X' % oldAddress) print('Missing ZeroBorg at %02X' % oldAddress)
if foundChip: if foundChip:
bus.RawWrite(COMMAND_SET_I2C_ADD, [newAddress]) bus.RawWrite(COMMAND_SET_I2C_ADD, [newAddress])
@ -188,8 +189,9 @@ Warning, this new I?C address will still be used after resetting the power on th
print('Missing ZeroBorg at %02X' % newAddress) print('Missing ZeroBorg at %02X' % newAddress)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
foundChip = False foundChip = False
print(str(e))
print('Missing ZeroBorg at %02X' % newAddress) print('Missing ZeroBorg at %02X' % newAddress)
if foundChip: if foundChip:
print('New I?C address of %02X set successfully' % newAddress) print('New I?C address of %02X set successfully' % newAddress)
@ -332,9 +334,9 @@ the current busNumber.
self.Print('Missing ZeroBorg at %02X' % self.i2cAddress) self.Print('Missing ZeroBorg at %02X' % self.i2cAddress)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.foundChip = False self.foundChip = False
self.Print('Missing ZeroBorg at %02X' % self.i2cAddress) self.Print('Missing ZeroBorg at %02X: %s' % (self.i2cAddress, str(e)))
# See if we are missing chips # See if we are missing chips
if not self.foundChip: if not self.foundChip:
@ -383,8 +385,8 @@ SetMotor1(1) -> motor 1 moving forward at 100% power
self.RawWrite(command, [pwm]) self.RawWrite(command, [pwm])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending motor 1 drive level!') self.Print('Failed sending motor 1 drive level! {}'.format(str(e)))
def GetMotor1(self): def GetMotor1(self):
""" """
@ -402,8 +404,8 @@ e.g.
i2cRecv = self.RawRead(COMMAND_GET_A, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_A, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading motor 1 drive level!') self.Print('Failed reading motor 1 drive level! {}'.format(str(e)))
return return
power = float(i2cRecv[2]) / float(PWM_MAX) power = float(i2cRecv[2]) / float(PWM_MAX)
@ -444,8 +446,8 @@ SetMotor2(1) -> motor 2 moving forward at 100% power
self.RawWrite(command, [pwm]) self.RawWrite(command, [pwm])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending motor 2 drive level!') self.Print('Failed sending motor 2 drive level! {}'.format(str(e)))
def GetMotor2(self): def GetMotor2(self):
""" """
@ -463,8 +465,8 @@ e.g.
i2cRecv = self.RawRead(COMMAND_GET_B, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_B, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading motor 2 drive level!') self.Print('Failed reading motor 2 drive level! {}'.format(str(e)))
return return
power = float(i2cRecv[2]) / float(PWM_MAX) power = float(i2cRecv[2]) / float(PWM_MAX)
@ -505,8 +507,8 @@ SetMotor3(1) -> motor 3 moving forward at 100% power
self.RawWrite(command, [pwm]) self.RawWrite(command, [pwm])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending motor 3 drive level!') self.Print('Failed sending motor 3 drive level! {}'.format(str(e)))
def GetMotor3(self): def GetMotor3(self):
""" """
@ -524,8 +526,8 @@ e.g.
i2cRecv = self.RawRead(COMMAND_GET_C, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_C, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading motor 3 drive level!') self.Print('Failed reading motor 3 drive level! {}'.format(str(e)))
return return
power = float(i2cRecv[2]) / float(PWM_MAX) power = float(i2cRecv[2]) / float(PWM_MAX)
@ -566,8 +568,8 @@ SetMotor4(1) -> motor 4 moving forward at 100% power
self.RawWrite(command, [pwm]) self.RawWrite(command, [pwm])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending motor 4 drive level!') self.Print('Failed sending motor 4 drive level! {}'.format(str(e)))
def GetMotor4(self): def GetMotor4(self):
""" """
@ -585,8 +587,8 @@ e.g.
i2cRecv = self.RawRead(COMMAND_GET_D, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_D, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading motor 4 drive level!') self.Print('Failed reading motor 4 drive level! {}'.format(str(e)))
return return
power = float(i2cRecv[2]) / float(PWM_MAX) power = float(i2cRecv[2]) / float(PWM_MAX)
@ -627,8 +629,8 @@ SetMotors(1) -> all motors are moving forward at 100% power
self.RawWrite(command, [pwm]) self.RawWrite(command, [pwm])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending all motors drive level!') self.Print('Failed sending all motors drive level! {}'.format(str(e)))
def MotorsOff(self): def MotorsOff(self):
""" """
@ -641,8 +643,8 @@ Sets all motors to stopped, useful when ending a program
self.RawWrite(COMMAND_ALL_OFF, [0]) self.RawWrite(COMMAND_ALL_OFF, [0])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending motors off command!') self.Print('Failed sending motors off command! {}'.format(str(e)))
def SetLed(self, state): def SetLed(self, state):
""" """
@ -674,8 +676,8 @@ Reads the current state of the LED, False for off, True for on
i2cRecv = self.RawRead(COMMAND_GET_LED, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_LED, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading LED state!') self.Print('Failed reading LED state! {}'.format(str(e)))
return return
if i2cRecv[1] == COMMAND_VALUE_OFF: if i2cRecv[1] == COMMAND_VALUE_OFF:
@ -694,8 +696,8 @@ Resets the EPO latch state, use to allow movement again after the EPO has been t
self.RawWrite(COMMAND_RESET_EPO, [0]) self.RawWrite(COMMAND_RESET_EPO, [0])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed resetting EPO!') self.Print('Failed resetting EPO! {}'.format(str(e)))
def GetEpo(self): def GetEpo(self):
""" """
@ -711,8 +713,8 @@ If True the EPO has been tripped, movement is disabled if the EPO is not ignored
i2cRecv = self.RawRead(COMMAND_GET_EPO, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_EPO, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading EPO ignore state!') self.Print('Failed reading EPO ignore state! {}'.format(str(e)))
return return
if i2cRecv[1] == COMMAND_VALUE_OFF: if i2cRecv[1] == COMMAND_VALUE_OFF:
@ -736,8 +738,8 @@ Sets the system to ignore or use the EPO latch, set to False if you have an EPO
self.RawWrite(COMMAND_SET_EPO_IGNORE, [level]) self.RawWrite(COMMAND_SET_EPO_IGNORE, [level])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending EPO ignore state!') self.Print('Failed sending EPO ignore state! {}'.format(str(e)))
def GetEpoIgnore(self): def GetEpoIgnore(self):
""" """
@ -750,8 +752,8 @@ Reads the system EPO ignore state, False for using the EPO latch, True for ignor
i2cRecv = self.RawRead(COMMAND_GET_EPO_IGNORE, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_EPO_IGNORE, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading EPO ignore state!') self.Print('Failed reading EPO ignore state! {}'.format(str(e)))
return return
if i2cRecv[1] == COMMAND_VALUE_OFF: if i2cRecv[1] == COMMAND_VALUE_OFF:
@ -793,8 +795,8 @@ Use HasNewIrMessage() to see if there has been a new IR message since the last c
i2cRecv = self.RawRead(COMMAND_GET_LAST_IR, I2C_LONG_LEN) i2cRecv = self.RawRead(COMMAND_GET_LAST_IR, I2C_LONG_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading IR message!') self.Print('Failed reading IR message! {}'.format(str(e)))
return return
message = '' message = ''
@ -818,8 +820,8 @@ Sets if IR messages control the state of the LED, False for no effect, True for
self.RawWrite(COMMAND_SET_LED_IR, [level]) self.RawWrite(COMMAND_SET_LED_IR, [level])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending LED state!') self.Print('Failed sending LED state! {}'.format(str(e)))
def GetLedIr(self): def GetLedIr(self):
""" """
@ -832,8 +834,8 @@ Reads if IR messages control the state of the LED, False for no effect, True for
i2cRecv = self.RawRead(COMMAND_GET_LED_IR, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_LED_IR, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading LED state!') self.Print('Failed reading LED state! {}'.format(str(e)))
return return
if i2cRecv[1] == COMMAND_VALUE_OFF: if i2cRecv[1] == COMMAND_VALUE_OFF:
@ -853,8 +855,8 @@ Returns the value as a voltage based on the 3.3 V reference pin (pin 1).
i2cRecv = self.RawRead(COMMAND_GET_ANALOG_1, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_ANALOG_1, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading analog level #1!') self.Print('Failed reading analog level #1! {}'.format(str(e)))
return return
raw = (i2cRecv[1] << 8) + i2cRecv[2] raw = (i2cRecv[1] << 8) + i2cRecv[2]
@ -873,8 +875,8 @@ Returns the value as a voltage based on the 3.3 V reference pin (pin 1).
i2cRecv = self.RawRead(COMMAND_GET_ANALOG_2, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_ANALOG_2, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading analog level #2!') self.Print('Failed reading analog level #2! {}'.format(str(e)))
return return
raw = (i2cRecv[1] << 8) + i2cRecv[2] raw = (i2cRecv[1] << 8) + i2cRecv[2]
@ -900,8 +902,8 @@ The failsafe is disabled at power on
self.RawWrite(COMMAND_SET_FAILSAFE, [level]) self.RawWrite(COMMAND_SET_FAILSAFE, [level])
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed sending communications failsafe state!') self.Print('Failed sending communications failsafe state! {}'.format(str(e)))
def GetCommsFailsafe(self): def GetCommsFailsafe(self):
""" """
@ -915,8 +917,8 @@ The failsafe will turn the motors off unless it is commanded at least once every
i2cRecv = self.RawRead(COMMAND_GET_FAILSAFE, I2C_NORM_LEN) i2cRecv = self.RawRead(COMMAND_GET_FAILSAFE, I2C_NORM_LEN)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except Exception as e:
self.Print('Failed reading communications failsafe state!') self.Print('Failed reading communications failsafe state! {}'.format(str(e)))
return return
if i2cRecv[1] == COMMAND_VALUE_OFF: if i2cRecv[1] == COMMAND_VALUE_OFF:
@ -930,6 +932,7 @@ Help()
Displays the names and descriptions of the various functions and settings provided Displays the names and descriptions of the various functions and settings provided
""" """
# noinspection PyTypeChecker
funcList = [ZeroBorg.__dict__.get(a) for a in dir(ZeroBorg) if funcList = [ZeroBorg.__dict__.get(a) for a in dir(ZeroBorg) if
isinstance(ZeroBorg.__dict__.get(a), types.FunctionType)] isinstance(ZeroBorg.__dict__.get(a), types.FunctionType)]
funcListSorted = sorted(funcList, key=lambda x: x.func_code.co_firstlineno) funcListSorted = sorted(funcList, key=lambda x: x.func_code.co_firstlineno)

View File

@ -1,42 +0,0 @@
import datetime
import dateutil.parser
from platypush.plugins import action
from platypush.plugins.http.request import HttpRequestPlugin
class HttpRequestOtaBookingPlugin(HttpRequestPlugin):
""" Plugin to send requests to the Booking Hub API """
def __init__(self, hotel_id, token, timeout=5, **kwargs):
self.hotel_id = hotel_id
self.token = token
self.timeout = timeout
@action
def get_reservations(self, day='today'):
url = 'https://hub-api.booking.com/v1/hotels/{}/reservations' \
.format(self.hotel_id)
today = datetime.date.today().isoformat()
if day == 'today': day = today
headers = { 'X-Booking-Auth-Token': self.token }
params = { 'checkin': day }
response = self.get(url, headers=headers, params=params,
output='json', timeout=self.timeout)
reservations = [res for res in response.output
if res['status'] != 'CANCELLED']
response.output = {
'reservations': reservations,
'n_reservations': len(reservations),
}
return response
# vim:sw=4:ts=4:et:

View File

@ -24,14 +24,12 @@ class HttpWebpagePlugin(Plugin):
_mercury_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mercury-parser.js') _mercury_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mercury-parser.js')
def _parse(self, proc): @staticmethod
output = '' def _parse(proc):
with subprocess.Popen(proc, stdout=subprocess.PIPE, stderr=None) as parser: with subprocess.Popen(proc, stdout=subprocess.PIPE, stderr=None) as parser:
output = parser.communicate()[0].decode() return parser.communicate()[0].decode()
return output
# noinspection PyShadowingBuiltins
@action @action
def simplify(self, url, type='html', html=None, outfile=None): def simplify(self, url, type='html', html=None, outfile=None):
""" """
@ -124,15 +122,12 @@ class HttpWebpagePlugin(Plugin):
weasyprint.HTML(string=content).write_pdf(outfile, stylesheets=css) weasyprint.HTML(string=content).write_pdf(outfile, stylesheets=css)
else: else:
content = ''' content = '''<html>
<html>
<head> <head>
<title>{title}</title> <title>{title}</title>
<style>{style}</style> <style>{style}</style>
</head> </head>'''.format(title=title, style=style, content=content) + \
<body>{{content}}</body> '<body>{{' + content + '}}</body></html>'
</html>
'''.format(title=title, style=style, content=content)
with open(outfile, 'w', encoding='utf-8') as f: with open(outfile, 'w', encoding='utf-8') as f:
f.write(content) f.write(content)

View File

@ -188,10 +188,10 @@ class InspectPlugin(Plugin):
for _, modname, _ in pkgutil.walk_packages(path=package.__path__, for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
prefix=prefix, prefix=prefix,
onerror=lambda x: None): onerror=lambda x: None):
# noinspection PyBroadException
try: try:
module = importlib.import_module(modname) module = importlib.import_module(modname)
except: except Exception as e:
self.logger.debug(f'Could not import module {modname}: {str(e)}')
continue continue
for _, obj in inspect.getmembers(module): for _, obj in inspect.getmembers(module):
@ -207,10 +207,10 @@ class InspectPlugin(Plugin):
for _, modname, _ in pkgutil.walk_packages(path=package.__path__, for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
prefix=prefix, prefix=prefix,
onerror=lambda x: None): onerror=lambda x: None):
# noinspection PyBroadException
try: try:
module = importlib.import_module(modname) module = importlib.import_module(modname)
except: except Exception as e:
self.logger.debug(f'Could not import module {modname}: {str(e)}')
continue continue
for _, obj in inspect.getmembers(module): for _, obj in inspect.getmembers(module):
@ -226,10 +226,10 @@ class InspectPlugin(Plugin):
for _, modname, _ in pkgutil.walk_packages(path=package.__path__, for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
prefix=prefix, prefix=prefix,
onerror=lambda x: None): onerror=lambda x: None):
# noinspection PyBroadException
try: try:
module = importlib.import_module(modname) module = importlib.import_module(modname)
except: except Exception as e:
self.logger.debug(f'Could not import module {modname}: {str(e)}')
continue continue
for _, obj in inspect.getmembers(module): for _, obj in inspect.getmembers(module):
@ -250,10 +250,10 @@ class InspectPlugin(Plugin):
for _, modname, _ in pkgutil.walk_packages(path=package.__path__, for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
prefix=prefix, prefix=prefix,
onerror=lambda x: None): onerror=lambda x: None):
# noinspection PyBroadException
try: try:
module = importlib.import_module(modname) module = importlib.import_module(modname)
except: except Exception as e:
self.logger.debug(f'Could not import module {modname}: {str(e)}')
continue continue
for _, obj in inspect.getmembers(module): for _, obj in inspect.getmembers(module):

View File

@ -1,6 +1,5 @@
import json import json
import logging import logging
import time
from platypush.context import get_backend from platypush.context import get_backend
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@ -19,10 +18,14 @@ class KafkaPlugin(Plugin):
* **kafka** (``pip install kafka-python``) * **kafka** (``pip install kafka-python``)
""" """
def __init__(self, server=None, **kwargs): def __init__(self, server=None, port=9092, **kwargs):
""" """
:param server: Default Kafka server name or address + port (format: ``host:port``) to dispatch the messages to. If None (default), then it has to be specified upon message sending. :param server: Default Kafka server name or address. If None (default), then it has to be specified upon
message sending.
:type server: str :type server: str
:param port: Default Kafka server port (default: 9092).
:type port: int
""" """
super().__init__(**kwargs) super().__init__(**kwargs)
@ -35,13 +38,17 @@ class KafkaPlugin(Plugin):
# Kafka can be veryyyy noisy # Kafka can be veryyyy noisy
logging.getLogger('kafka').setLevel(logging.ERROR) logging.getLogger('kafka').setLevel(logging.ERROR)
@action @action
def send_message(self, msg, topic, server=None, **kwargs): def send_message(self, msg, topic, server=None):
""" """
:param msg: Message to send - as a string, bytes stream, JSON, Platypush message, dictionary, or anything that implements ``__str__`` :param msg: Message to send - as a string, bytes stream, JSON, Platypush message, dictionary, or anything
that implements ``__str__``
:param server: Kafka server name or address + port (format: ``host:port``). If None, then the default server will be used :param topic: Topic to send the message to.
:type topic: str
:param server: Kafka server name or address + port (format: ``host:port``). If None, then the default server
will be used
:type server: str :type server: str
""" """
@ -52,8 +59,8 @@ class KafkaPlugin(Plugin):
try: try:
kafka_backend = get_backend('kafka') kafka_backend = get_backend('kafka')
server = kafka_backend.server server = kafka_backend.server
except: except Exception as e:
raise RuntimeError('No Kafka server nor default server specified') raise RuntimeError(f'No Kafka server nor default server specified: {str(e)}')
else: else:
server = self.server server = self.server
@ -67,4 +74,3 @@ class KafkaPlugin(Plugin):
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -3,9 +3,9 @@ import functools
import os import os
import queue import queue
import re import re
import requests
from typing import Optional, List, Dict, Union from typing import Optional, List, Dict, Union
import requests
import subprocess import subprocess
import tempfile import tempfile
import threading import threading
@ -214,8 +214,8 @@ class MediaPlugin(Plugin):
try: try:
torrents = get_plugin(self.torrent_plugin) torrents = get_plugin(self.torrent_plugin)
torrents.quit() torrents.quit()
except: except Exception as e:
pass self.logger.warning(f'Could not stop torrent plugin: {str(e)}')
@action @action
def play(self, resource, *args, **kwargs): def play(self, resource, *args, **kwargs):
@ -423,7 +423,6 @@ class MediaPlugin(Plugin):
} }
""" """
import requests
http = get_backend('http') http = get_backend('http')
if not http: if not http:
@ -445,8 +444,6 @@ class MediaPlugin(Plugin):
@action @action
def stop_streaming(self, media_id): def stop_streaming(self, media_id):
import requests
http = get_backend('http') http = get_backend('http')
if not http: if not http:
self.logger.warning('Cannot unregister {}: HTTP backend unavailable'. self.logger.warning('Cannot unregister {}: HTTP backend unavailable'.
@ -536,9 +533,9 @@ class MediaPlugin(Plugin):
return functools.reduce( return functools.reduce(
lambda t, t_i: t + t_i, lambda t, t_i: t + t_i,
[float(t) * pow(60, i) for (i, t) in enumerate(re.search( [float(t) * pow(60, i) for (i, t) in enumerate(re.search(
'^Duration:\s*([^,]+)', [x.decode() r'^Duration:\s*([^,]+)', [x.decode()
for x in result.stdout.readlines() for x in result.stdout.readlines()
if "Duration" in x.decode()].pop().strip() if "Duration" in x.decode()].pop().strip()
).group(1).split(':')[::-1])] ).group(1).split(':')[::-1])]
) )

View File

@ -2,7 +2,7 @@ import datetime
import re import re
import time import time
from platypush.context import get_plugin, get_bus from platypush.context import get_bus
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.media import MediaPlugin from platypush.plugins.media import MediaPlugin
from platypush.utils import get_mime_type from platypush.utils import get_mime_type
@ -91,6 +91,7 @@ class MediaChromecastPlugin(MediaPlugin):
post_event(MediaStopEvent, device=self.name) post_event(MediaStopEvent, device=self.name)
if status.get('volume') != self.status.get('volume'): if status.get('volume') != self.status.get('volume'):
post_event(MediaVolumeChangedEvent, volume=status.get('volume'), device=self.name) post_event(MediaVolumeChangedEvent, volume=status.get('volume'), device=self.name)
# noinspection PyUnresolvedReferences
if abs(status.get('position') - self.status.get('position')) > time.time() - self.last_status_timestamp + 5: if abs(status.get('position') - self.status.get('position')) > time.time() - self.last_status_timestamp + 5:
post_event(MediaSeekEvent, position=status.get('position'), device=self.name) post_event(MediaSeekEvent, position=status.get('position'), device=self.name)
@ -104,7 +105,7 @@ class MediaChromecastPlugin(MediaPlugin):
self.initialized = False self.initialized = False
# pylint: disable=unused-argument # pylint: disable=unused-argument
def new_media_status(self, status): def new_media_status(self, *_):
if self.subtitle_id and not self.initialized: if self.subtitle_id and not self.initialized:
self.mc.update_status() self.mc.update_status()
self.mc.enable_subtitle(self.subtitle_id) self.mc.enable_subtitle(self.subtitle_id)
@ -327,9 +328,9 @@ class MediaChromecastPlugin(MediaPlugin):
@classmethod @classmethod
def _get_youtube_url(cls, url): def _get_youtube_url(cls, url):
m = re.match('https?://www.youtube.com/watch\?v=([^&]+).*', url) m = re.match(r'https?://(www\.)?youtube\.com/watch\?v=([^&]+).*', url)
if m: if m:
return m.group(1) return m.group(2)
m = re.match('youtube:video:(.*)', url) m = re.match('youtube:video:(.*)', url)
if m: if m:

View File

@ -1,5 +1,4 @@
import json import json
import re
import threading import threading
import time import time
@ -7,7 +6,7 @@ from platypush.context import get_bus
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.media import MediaPlugin, PlayerState from platypush.plugins.media import MediaPlugin, PlayerState
from platypush.message.event.media import MediaPlayEvent, MediaPauseEvent, MediaStopEvent, \ from platypush.message.event.media import MediaPlayEvent, MediaPauseEvent, MediaStopEvent, \
MediaSeekEvent, MediaVolumeChangedEvent, NewPlayingMediaEvent MediaSeekEvent, MediaVolumeChangedEvent
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
@ -602,7 +601,8 @@ class MediaKodiPlugin(MediaPlugin):
try: try:
kodi = self._get_kodi() kodi = self._get_kodi()
players = kodi.Player.GetActivePlayers().get('result', []) players = kodi.Player.GetActivePlayers().get('result', [])
except: except Exception as e:
self.logger.debug(f'Could not get active players: {str(e)}')
return ret return ret
ret['state'] = PlayerState.STOP.value ret['state'] = PlayerState.STOP.value

View File

@ -1,5 +1,4 @@
import enum import enum
import math
import urllib.parse import urllib.parse
from platypush.context import get_bus from platypush.context import get_bus
@ -119,8 +118,8 @@ class MediaOmxplayerPlugin(MediaPlugin):
try: try:
try: try:
self._player.stop() self._player.stop()
except: except Exception as e:
pass self.logger.warning(f'Could not stop player: {str(e)}')
self._player.quit() self._player.quit()
except OMXPlayerDeadError: except OMXPlayerDeadError:

View File

@ -3,9 +3,7 @@ import os
import re import re
import time import time
from sqlalchemy import create_engine, func, or_, Column, Integer, String, \ from sqlalchemy import create_engine, Column, Integer, String, DateTime, PrimaryKeyConstraint, ForeignKey
DateTime, PrimaryKeyConstraint, ForeignKey
from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
@ -17,6 +15,7 @@ from platypush.plugins.media.search import MediaSearcher
Base = declarative_base() Base = declarative_base()
Session = scoped_session(sessionmaker()) Session = scoped_session(sessionmaker())
class LocalMediaSearcher(MediaSearcher): class LocalMediaSearcher(MediaSearcher):
""" """
This class will search for media in the local configured directories. It This class will search for media in the local configured directories. It
@ -29,7 +28,7 @@ class LocalMediaSearcher(MediaSearcher):
* **sqlalchemy** (``pip install sqlalchemy``) * **sqlalchemy** (``pip install sqlalchemy``)
""" """
_filename_separators = '[.,_\-@()\[\]\{\}\s\'\"]+' _filename_separators = r'[.,_\-@()\[\]\{\}\s\'\"]+'
def __init__(self, dirs, *args, **kwargs): def __init__(self, dirs, *args, **kwargs):
super().__init__() super().__init__()

View File

@ -97,8 +97,8 @@ class MediaWebtorrentPlugin(MediaPlugin):
if Config.get(plugin_name): if Config.get(plugin_name):
self._media_plugin = get_plugin(plugin_name) self._media_plugin = get_plugin(plugin_name)
break break
except: except Exception as e:
pass self.logger.debug(f'Could not get media plugin {plugin_name}: {str(e)}')
if not self._media_plugin: if not self._media_plugin:
raise RuntimeError(('No media player specified and no ' + raise RuntimeError(('No media player specified and no ' +
@ -109,7 +109,7 @@ class MediaWebtorrentPlugin(MediaPlugin):
def _read_process_line(self): def _read_process_line(self):
line = self._webtorrent_process.stdout.readline().decode().strip() line = self._webtorrent_process.stdout.readline().decode().strip()
# Strip output of the colors # Strip output of the colors
return re.sub('\x1b\[(([0-9]+m)|(.{1,2}))', '', line).strip() return re.sub(r'\x1b\[(([0-9]+m)|(.{1,2}))', '', line).strip()
def _process_monitor(self, resource, download_dir, download_only, def _process_monitor(self, resource, download_dir, download_only,
player_type, player_args): player_type, player_args):
@ -142,7 +142,7 @@ class MediaWebtorrentPlugin(MediaPlugin):
and state == TorrentState.IDLE: and state == TorrentState.IDLE:
# IDLE -> DOWNLOADING_METADATA # IDLE -> DOWNLOADING_METADATA
state = TorrentState.DOWNLOADING_METADATA state = TorrentState.DOWNLOADING_METADATA
bus.post(TorrentDownloadedMetadataEvent(resource=resource)) bus.post(TorrentDownloadedMetadataEvent(url=webtorrent_url, resource=resource))
elif 'downloading: ' in line.lower() \ elif 'downloading: ' in line.lower() \
and media_file is None: and media_file is None:
# Find video files in torrent directory # Find video files in torrent directory
@ -177,10 +177,9 @@ class MediaWebtorrentPlugin(MediaPlugin):
if state.value <= TorrentState.DOWNLOADING_METADATA.value \ if state.value <= TorrentState.DOWNLOADING_METADATA.value \
and media_file and webtorrent_url: and media_file and webtorrent_url:
# DOWNLOADING_METADATA -> DOWNLOADING # DOWNLOADING_METADATA -> DOWNLOADING
state = TorrentState.DOWNLOADING
bus.post(TorrentDownloadStartEvent( bus.post(TorrentDownloadStartEvent(
resource=resource, media_file=media_file, resource=resource, media_file=media_file,
stream_url=webtorrent_url)) stream_url=webtorrent_url, url=webtorrent_url))
break break
if not output_dir: if not output_dir:
@ -193,8 +192,11 @@ class MediaWebtorrentPlugin(MediaPlugin):
self.logger.warning('WebTorrent could not start streaming') self.logger.warning('WebTorrent could not start streaming')
# Keep downloading but don't start the player # Keep downloading but don't start the player
try: self._webtorrent_process.wait() try:
except: pass self._webtorrent_process.wait()
except Exception as e:
self.logger.warning(f'WebTorrent process error: {str(e)}')
return return
player = None player = None
@ -237,10 +239,14 @@ class MediaWebtorrentPlugin(MediaPlugin):
self.logger.info('Torrent player terminated') self.logger.info('Torrent player terminated')
bus.post(TorrentDownloadCompletedEvent(resource=resource, bus.post(TorrentDownloadCompletedEvent(resource=resource,
output_dir=output_dir, output_dir=output_dir,
media_file=media_file)) media_file=media_file,
url=webtorrent_url))
try:
self.quit()
except Exception as e:
self.logger.warning(f'Could not terminate WebTorrent process: {str(e)}')
try: self.quit()
except: pass
self.logger.info('WebTorrent process terminated') self.logger.info('WebTorrent process terminated')
return _thread return _thread
@ -252,6 +258,7 @@ class MediaWebtorrentPlugin(MediaPlugin):
media_cls = player.__class__.__name__ media_cls = player.__class__.__name__
if media_cls == 'MediaMplayerPlugin': if media_cls == 'MediaMplayerPlugin':
# noinspection PyProtectedMember
stop_evt = player._mplayer_stopped_event stop_evt = player._mplayer_stopped_event
elif media_cls == 'MediaMpvPlugin' or media_cls == 'MediaVlcPlugin': elif media_cls == 'MediaMpvPlugin' or media_cls == 'MediaVlcPlugin':
stop_evt = threading.Event() stop_evt = threading.Event()
@ -359,8 +366,8 @@ class MediaWebtorrentPlugin(MediaPlugin):
stream_url = self._torrent_stream_urls.get(resource) stream_url = self._torrent_stream_urls.get(resource)
if not stream_url: if not stream_url:
return (None, ('The webtorrent process hasn\'t started ' + return (None, ("The webtorrent process hasn't started " +
'streaming after {} seconds').format( "streaming after {} seconds").format(
self._web_stream_ready_timeout)) self._web_stream_ready_timeout))
return {'resource': resource, 'url': stream_url} return {'resource': resource, 'url': stream_url}
@ -380,8 +387,10 @@ class MediaWebtorrentPlugin(MediaPlugin):
if self._is_process_alive(): if self._is_process_alive():
self._webtorrent_process.terminate() self._webtorrent_process.terminate()
self._webtorrent_process.wait() self._webtorrent_process.wait()
try: self._webtorrent_process.kill() try:
except: pass self._webtorrent_process.kill()
except Exception as e:
self.logger.warning(f'Error on WebTorrent process kill: {str(e)}')
self._webtorrent_process = None self._webtorrent_process = None

View File

@ -173,11 +173,10 @@ class MqttPlugin(Plugin):
if isinstance(msg, (dict, list)): if isinstance(msg, (dict, list)):
msg = json.dumps(msg) msg = json.dumps(msg)
# noinspection PyBroadException
try: try:
msg = Message.build(json.loads(msg)) msg = Message.build(json.loads(msg))
except: except Exception as e:
pass self.logger.debug(f'Not a valid JSON: {str(e)}')
host = host or self.host host = host or self.host
port = port or self.port or 1883 port = port or self.port or 1883
@ -209,11 +208,10 @@ class MqttPlugin(Plugin):
response_buffer.close() response_buffer.close()
if client: if client:
# noinspection PyBroadException
try: try:
client.loop_stop() client.loop_stop()
except: except Exception as e:
pass self.logger.warning(f'Could not stop client loop: {e}')
client.disconnect() client.disconnect()

View File

@ -62,7 +62,8 @@ class MusicMpdPlugin(MusicPlugin):
time.sleep(0.5) time.sleep(0.5)
self.client = None self.client = None
raise error if error:
raise error
def _exec(self, method, *args, **kwargs): def _exec(self, method, *args, **kwargs):
error = None error = None
@ -383,14 +384,14 @@ class MusicMpdPlugin(MusicPlugin):
if not resource: if not resource:
return return
m = re.search('^https://open.spotify.com/([^?]+)', resource) m = re.search(r'^https?://open\.spotify\.com/([^?]+)', resource)
if m: if m:
resource = 'spotify:{}'.format(m.group(1).replace('/', ':')) resource = 'spotify:{}'.format(m.group(1).replace('/', ':'))
if resource.startswith('spotify:'): if resource.startswith('spotify:'):
resource = resource.split('?')[0] resource = resource.split('?')[0]
m = re.match('spotify:playlist:(.*)', resource) m = re.match(r'spotify:playlist:(.*)', resource)
if m: if m:
# Old Spotify URI format, convert it to new # Old Spotify URI format, convert it to new
resource = 'spotify:user:spotify:playlist:' + m.group(1) resource = 'spotify:user:spotify:playlist:' + m.group(1)
@ -423,8 +424,8 @@ class MusicMpdPlugin(MusicPlugin):
""" """
Seek to the specified position (DEPRECATED, use :meth:`.seek` instead). Seek to the specified position (DEPRECATED, use :meth:`.seek` instead).
:param value: Seek position in seconds, or delta string (e.g. '+15' or '-15') to indicate a seek relative to the current position :param value: Seek position in seconds, or delta string (e.g. '+15' or '-15') to indicate a seek relative to
:type value: int the current position :type value: int
""" """
return self.seek(value) return self.seek(value)
@ -434,8 +435,8 @@ class MusicMpdPlugin(MusicPlugin):
""" """
Seek to the specified position Seek to the specified position
:param position: Seek position in seconds, or delta string (e.g. '+15' or '-15') to indicate a seek relative to the current position :param position: Seek position in seconds, or delta string (e.g. '+15' or '-15') to indicate a seek relative
:type position: int to the current position :type position: int
""" """
return self._exec('seekcur', position) return self._exec('seekcur', position)
@ -486,7 +487,8 @@ class MusicMpdPlugin(MusicPlugin):
try: try:
n_tries -= 1 n_tries -= 1
self._connect() self._connect()
return self.client.status() if self.client:
return self.client.status()
except Exception as e: except Exception as e:
error = e error = e
self.logger.warning('Exception while getting MPD status: {}'. self.logger.warning('Exception while getting MPD status: {}'.
@ -523,7 +525,7 @@ class MusicMpdPlugin(MusicPlugin):
or not track['artist'] or not track['artist']
or re.search('^https?://', track['file']) or re.search('^https?://', track['file'])
or re.search('^tunein:', track['file'])): or re.search('^tunein:', track['file'])):
m = re.match('^\s*(.+?)\s+-\s+(.*)\s*$', track['title']) m = re.match(r'^\s*(.+?)\s+-\s+(.*)\s*$', track['title'])
if m and m.group(1) and m.group(2): if m and m.group(1) and m.group(2):
track['artist'] = m.group(1) track['artist'] = m.group(1)
track['title'] = m.group(2) track['title'] = m.group(2)
@ -781,10 +783,7 @@ class MusicMpdPlugin(MusicPlugin):
items = self._exec('search', *filter, *args, return_status=False, **kwargs) items = self._exec('search', *filter, *args, return_status=False, **kwargs)
# Spotify results first # Spotify results first
items = sorted(items, key=lambda item: return sorted(items, key=lambda item: 0 if item['file'].startswith('spotify:') else 1)
0 if item['file'].startswith('spotify:') else 1)
return items
# noinspection PyShadowingBuiltins # noinspection PyShadowingBuiltins
@action @action

View File

@ -96,6 +96,7 @@ class MusicSnapcastPlugin(Plugin):
'method': 'Server.GetStatus' 'method': 'Server.GetStatus'
} }
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return (self._recv(sock) or {}).get('server', {}) return (self._recv(sock) or {}).get('server', {})
@ -214,8 +215,8 @@ class MusicSnapcastPlugin(Plugin):
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning(f'Error on socket close: {e}')
@action @action
def mute(self, client=None, group=None, mute=None, host=None, port=None): def mute(self, client=None, group=None, mute=None, host=None, port=None):
@ -266,13 +267,14 @@ class MusicSnapcastPlugin(Plugin):
request['params']['volume']['percent'] = client['config']['volume']['percent'] request['params']['volume']['percent'] = client['config']['volume']['percent']
request['params']['volume']['muted'] = not cur_muted if mute is None else mute request['params']['volume']['muted'] = not cur_muted if mute is None else mute
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def volume(self, client, volume=None, delta=None, mute=None, host=None, def volume(self, client, volume=None, delta=None, mute=None, host=None,
@ -336,13 +338,14 @@ class MusicSnapcastPlugin(Plugin):
request['params']['volume'] = {} request['params']['volume'] = {}
request['params']['volume']['percent'] = volume request['params']['volume']['percent'] = volume
request['params']['volume']['muted'] = mute request['params']['volume']['muted'] = mute
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def set_client_name(self, client, name, host=None, port=None): def set_client_name(self, client, name, host=None, port=None):
@ -376,13 +379,14 @@ class MusicSnapcastPlugin(Plugin):
client = self._get_client(sock, client) client = self._get_client(sock, client)
request['params']['id'] = client['id'] request['params']['id'] = client['id']
request['params']['name'] = name request['params']['name'] = name
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def set_group_name(self, group, name, host=None, port=None): def set_group_name(self, group, name, host=None, port=None):
@ -416,13 +420,14 @@ class MusicSnapcastPlugin(Plugin):
} }
} }
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def set_latency(self, client, latency, host=None, port=None): def set_latency(self, client, latency, host=None, port=None):
@ -457,13 +462,14 @@ class MusicSnapcastPlugin(Plugin):
client = self._get_client(sock, client) client = self._get_client(sock, client)
request['params']['id'] = client['id'] request['params']['id'] = client['id']
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def delete_client(self, client, host=None, port=None): def delete_client(self, client, host=None, port=None):
@ -493,13 +499,14 @@ class MusicSnapcastPlugin(Plugin):
client = self._get_client(sock, client) client = self._get_client(sock, client)
request['params']['id'] = client['id'] request['params']['id'] = client['id']
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def group_set_clients(self, group, clients, host=None, port=None): def group_set_clients(self, group, clients, host=None, port=None):
@ -538,13 +545,14 @@ class MusicSnapcastPlugin(Plugin):
client = self._get_client(sock, client) client = self._get_client(sock, client)
request['params']['clients'].append(client['id']) request['params']['clients'].append(client['id'])
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def group_set_stream(self, group, stream_id, host=None, port=None): def group_set_stream(self, group, stream_id, host=None, port=None):
@ -579,13 +587,14 @@ class MusicSnapcastPlugin(Plugin):
} }
} }
# noinspection PyTypeChecker
self._send(sock, request) self._send(sock, request)
return self._recv(sock) return self._recv(sock)
finally: finally:
try: try:
sock.close() sock.close()
except: except Exception as e:
pass self.logger.warning('Error on socket close', e)
@action @action
def get_backend_hosts(self): def get_backend_hosts(self):

View File

@ -1,6 +1,5 @@
import json import json
import os import os
from typing import Optional
import requests import requests
@ -101,6 +100,7 @@ class PushbulletPlugin(Plugin):
kwargs['type'] = 'link' if url else 'note' kwargs['type'] = 'link' if url else 'note'
if device: if device:
# noinspection PyTypeChecker
kwargs['device_iden'] = device['iden'] kwargs['device_iden'] = device['iden']
resp = requests.post('https://api.pushbullet.com/v2/pushes', resp = requests.post('https://api.pushbullet.com/v2/pushes',
@ -143,6 +143,7 @@ class PushbulletPlugin(Plugin):
raise Exception('Pushbullet file upload failed with status {}'. raise Exception('Pushbullet file upload failed with status {}'.
format(resp.status_code)) format(resp.status_code))
# noinspection PyTypeChecker
resp = requests.post('https://api.pushbullet.com/v2/pushes', resp = requests.post('https://api.pushbullet.com/v2/pushes',
headers={'Authorization': 'Bearer ' + self.token, headers={'Authorization': 'Bearer ' + self.token,
'Content-Type': 'application/json'}, 'Content-Type': 'application/json'},

View File

@ -19,13 +19,12 @@ class RedisPlugin(Plugin):
self.kwargs = kwargs self.kwargs = kwargs
if not kwargs: if not kwargs:
# noinspection PyBroadException
try: try:
redis_backend = get_backend('redis') redis_backend = get_backend('redis')
if redis_backend and redis_backend.redis_args: if redis_backend and redis_backend.redis_args:
self.kwargs = redis_backend.redis_args self.kwargs = redis_backend.redis_args
except: except Exception as e:
pass self.logger.debug(e)
def _get_redis(self): def _get_redis(self):
return Redis(*self.args, **self.kwargs) return Redis(*self.args, **self.kwargs)

View File

@ -8,7 +8,6 @@ from platypush.plugins import action
from platypush.plugins.sensor import SensorPlugin from platypush.plugins.sensor import SensorPlugin
# noinspection PyBroadException
class SerialPlugin(SensorPlugin): class SerialPlugin(SensorPlugin):
""" """
The serial plugin can read data from a serial device, as long as the serial The serial plugin can read data from a serial device, as long as the serial
@ -129,7 +128,8 @@ class SerialPlugin(SensorPlugin):
if serial_available: if serial_available:
try: try:
ser = self._get_serial(device=device, baud_rate=baud_rate) ser = self._get_serial(device=device, baud_rate=baud_rate)
except: except Exception as e:
self.logger.debug(e)
time.sleep(1) time.sleep(1)
ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True) ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True)
@ -137,16 +137,15 @@ class SerialPlugin(SensorPlugin):
try: try:
data = json.loads(data) data = json.loads(data)
except: except (ValueError, TypeError):
self.logger.warning('Invalid JSON message from {}: {}'. self.logger.warning('Invalid JSON message from {}: {}'.format(self.device, data))
format(self.device, data))
else: else:
data = self.last_measurement data = self.last_measurement
finally: finally:
try: try:
self.serial_lock.release() self.serial_lock.release()
except: except Exception as e:
pass self.logger.debug(e)
if data: if data:
self.last_measurement = data self.last_measurement = data
@ -194,7 +193,8 @@ class SerialPlugin(SensorPlugin):
if serial_available: if serial_available:
try: try:
ser = self._get_serial(device=device, baud_rate=baud_rate) ser = self._get_serial(device=device, baud_rate=baud_rate)
except: except Exception as e:
self.logger.debug(e)
time.sleep(1) time.sleep(1)
ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True) ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True)
@ -216,12 +216,12 @@ class SerialPlugin(SensorPlugin):
finally: finally:
try: try:
self.serial_lock.release() self.serial_lock.release()
except: except Exception as e:
pass self.logger.debug(e)
try: try:
data = data.decode() data = data.decode()
except: except (ValueError, TypeError):
data = base64.encodebytes(data) data = base64.encodebytes(data)
return data return data
@ -261,7 +261,8 @@ class SerialPlugin(SensorPlugin):
if serial_available: if serial_available:
try: try:
ser = self._get_serial(device=device, baud_rate=baud_rate) ser = self._get_serial(device=device, baud_rate=baud_rate)
except: except Exception as e:
self.logger.debug(e)
time.sleep(1) time.sleep(1)
ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True) ser = self._get_serial(device=device, baud_rate=baud_rate, reset=True)
@ -270,8 +271,8 @@ class SerialPlugin(SensorPlugin):
finally: finally:
try: try:
self.serial_lock.release() self.serial_lock.release()
except: except Exception as e:
pass self.logger.debug(e)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -166,8 +166,7 @@ class SoundPlugin(Plugin):
is_raw_stream = streamtype == sd.RawOutputStream is_raw_stream = streamtype == sd.RawOutputStream
# noinspection PyUnusedLocal def audio_callback(outdata, frames, *, status):
def audio_callback(outdata, frames, frame_time, status):
if self._get_playback_state(stream_index) == PlaybackState.STOPPED: if self._get_playback_state(stream_index) == PlaybackState.STOPPED:
raise sd.CallbackStop raise sd.CallbackStop
@ -181,7 +180,7 @@ class SoundPlugin(Plugin):
if status.output_underflow: if status.output_underflow:
self.logger.warning('Output underflow: increase blocksize?') self.logger.warning('Output underflow: increase blocksize?')
outdata = (b'\x00' if is_raw_stream else 0.) * len(outdata) outdata[:] = (b'\x00' if is_raw_stream else 0.) * len(outdata)
return return
if status: if status:
@ -397,7 +396,6 @@ class SoundPlugin(Plugin):
finally: finally:
if f and not f.closed: if f and not f.closed:
f.close() f.close()
f = None
self.stop_playback([stream_index]) self.stop_playback([stream_index])

View File

@ -221,10 +221,9 @@ class SshPlugin(Plugin):
client = self._connect(**kwargs) client = self._connect(**kwargs)
def decode(buf: bytes) -> str: def decode(buf: bytes) -> str:
# noinspection PyBroadException
try: try:
buf = buf.decode() buf = buf.decode()
except: except (ValueError, TypeError):
buf = base64.encodebytes(buf).decode() buf = base64.encodebytes(buf).decode()
if buf.endswith('\n'): if buf.endswith('\n'):
@ -341,11 +340,10 @@ class SshPlugin(Plugin):
try: try:
if os.path.isdir(local_path): if os.path.isdir(local_path):
# noinspection PyBroadException
try: try:
sftp.mkdir(remote_path) sftp.mkdir(remote_path)
except: except Exception as e:
pass self.logger.warning(f'mkdir {remote_path}: {e}')
assert recursive, '{} is a directory but recursive has been set to False'.format(local_path) assert recursive, '{} is a directory but recursive has been set to False'.format(local_path)
assert self.is_directory(sftp, remote_path), \ assert self.is_directory(sftp, remote_path), \
@ -355,11 +353,10 @@ class SshPlugin(Plugin):
os.chdir(local_path) os.chdir(local_path)
for path, folders, files in os.walk('.'): for path, folders, files in os.walk('.'):
# noinspection PyBroadException
try: try:
sftp.mkdir(path) sftp.mkdir(path)
except: except Exception as e:
pass self.logger.warning(f'mkdir {remote_path}: {e}')
for file in files: for file in files:
src = os.path.join(path, file) src = os.path.join(path, file)

View File

@ -47,12 +47,11 @@ def reverse_tunnel(server_port, remote_host, remote_port, transport, bind_addr='
should_run[key] = True should_run[key] = True
while should_run.get(key): while should_run.get(key):
# noinspection PyBroadException
try: try:
chan = transport.accept(1) chan = transport.accept(1)
if chan is None: assert chan is not None
raise AssertionError except Exception as e:
except: logger.warning(e)
continue continue
thr = threading.Thread( thr = threading.Thread(

View File

@ -128,7 +128,6 @@ class SwitchSwitchbotPlugin(SwitchPlugin, BluetoothBlePlugin):
compatible_devices = {} compatible_devices = {}
for dev in devices: for dev in devices:
# noinspection PyBroadException
try: try:
characteristics = [ characteristics = [
chrc for chrc in self.discover_characteristics( chrc for chrc in self.discover_characteristics(
@ -139,8 +138,8 @@ class SwitchSwitchbotPlugin(SwitchPlugin, BluetoothBlePlugin):
if characteristics: if characteristics:
compatible_devices[dev['addr']] = None compatible_devices[dev['addr']] = None
except: except Exception as e:
pass self.logger.warning('Device scan error', e)
return BluetoothScanResponse(devices=compatible_devices) return BluetoothScanResponse(devices=compatible_devices)

View File

@ -83,11 +83,10 @@ class TensorflowPlugin(Plugin):
assert success, 'Unable to acquire the model lock' assert success, 'Unable to acquire the model lock'
yield yield
finally: finally:
# noinspection PyBroadException
try: try:
self._model_locks[model_name].release() self._model_locks[model_name].release()
except: except Exception as e:
pass self.logger.info(f'Model {model_name} lock release error: {e}')
def _load_model(self, model_name: str, reload: bool = False) -> Model: def _load_model(self, model_name: str, reload: bool = False) -> Model:
if model_name in self.models and not reload: if model_name in self.models and not reload:

View File

@ -1,5 +1,5 @@
import requests import requests
from typing import Callable, Dict, Any, List, Optional from typing import Callable, Dict, Any, List
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action

View File

@ -1,93 +0,0 @@
import json
import urllib3
import urllib.request
import urllib.parse
from platypush.plugins import Plugin, action
from platypush.plugins.media import PlayerState
class VideoTorrentcastPlugin(Plugin):
def __init__(self, server='localhost', port=9090, *args, **kwargs):
self.server = server
self.port = port
self.state = PlayerState.STOP.value
@action
def play(self, url):
request = urllib.request.urlopen(
'http://{}:{}/play/'.format(self.server, self.port),
data=urllib.parse.urlencode({
'url': url
}).encode()
)
self.state = PlayerState.PLAY.value
return request.read()
@action
def pause(self):
http = urllib3.PoolManager()
request = http.request('POST',
'http://{}:{}/pause/'.format(self.server, self.port))
self.state = PlayerState.PAUSE.value
return request.read()
@action
def stop(self):
http = urllib3.PoolManager()
request = http.request('POST',
'http://{}:{}/stop/'.format(self.server, self.port))
self.state = PlayerState.STOP.value
return request.read()
@action
def search(self, query):
request = urllib.request.urlopen(urllib.request.Request(
'https://api.apidomain.info/list?' + urllib.parse.urlencode({
'sort': 'relevance',
'quality': '720p,1080p,3d',
'page': 1,
'keywords': query,
}),
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ' +
'(KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
})
)
results = json.loads(request.read())
return results
@action
def search_and_play(self, query):
response = self.search(query)
if not response.output['MovieList']:
self.logger.info('No torrent results found for {}'.format(query))
item = response.output['MovieList'][0]
magnet = item['items'][0]['torrent_magnet']
self.logger.info('Playing torrent "{}" from {}'
.format(item['title'], magnet))
return self.play(magnet)
@action
def voldown(self): raise NotImplementedError()
@action
def volup(self): raise NotImplementedError()
@action
def back(self): raise NotImplementedError()
@action
def forward(self): raise NotImplementedError()
@action
def status(self): return { 'state': self.state }
# vim:sw=4:ts=4:et:

View File

@ -3,8 +3,7 @@ import socket
import time import time
from typing import List, Dict, Any, Optional, Union from typing import List, Dict, Any, Optional, Union
import zeroconf from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser, ServiceListener, ZeroconfServiceTypes
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
from platypush.context import get_bus from platypush.context import get_bus
from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent, \ from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent, \
@ -12,7 +11,7 @@ from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, Zeroconf
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
class ZeroconfListener(zeroconf.ServiceListener): class ZeroconfListener(ServiceListener):
def __init__(self, evt_queue: queue.Queue): def __init__(self, evt_queue: queue.Queue):
super().__init__() super().__init__()
self.evt_queue = evt_queue self.evt_queue = evt_queue
@ -79,7 +78,7 @@ class ZeroconfPlugin(Plugin):
:param timeout: Discovery timeout in seconds (default: 5). :param timeout: Discovery timeout in seconds (default: 5).
:return: List of the services as strings. :return: List of the services as strings.
""" """
return list(zeroconf.ZeroconfServiceTypes.find(timeout=timeout)) return list(ZeroconfServiceTypes.find(timeout=timeout))
@action @action
def discover_service(self, service: Union[str, list], timeout: Optional[int] = 5) -> Dict[str, Any]: def discover_service(self, service: Union[str, list], timeout: Optional[int] = 5) -> Dict[str, Any]:

View File

@ -125,9 +125,10 @@ class ZigbeeMqttPlugin(MqttPlugin, SwitchPlugin):
:param password: If the connection requires user authentication, specify the password (default: None) :param password: If the connection requires user authentication, specify the password (default: None)
""" """
super().__init__(host=host, port=port, tls_certfile=tls_certfile, tls_keyfile=tls_keyfile, SwitchPlugin.__init__(self)
tls_version=tls_version, tls_ciphers=tls_ciphers, username=username, MqttPlugin.__init__(self, host=host, port=port, tls_certfile=tls_certfile, tls_keyfile=tls_keyfile,
password=password, **kwargs) tls_version=tls_version, tls_ciphers=tls_ciphers, username=username,
password=password, **kwargs)
self.base_topic = base_topic self.base_topic = base_topic
self.timeout = timeout self.timeout = timeout

View File

@ -270,12 +270,12 @@ class ForProcedure(LoopProcedure):
self.iterable = iterable self.iterable = iterable
def execute(self, _async=None, **context): def execute(self, _async=None, **context):
# noinspection PyBroadException
try: try:
iterable = eval(self.iterable) iterable = eval(self.iterable)
assert hasattr(iterable, '__iter__'), 'Object of type {} is not iterable: {}'.\ assert hasattr(iterable, '__iter__'), 'Object of type {} is not iterable: {}'.\
format(type(iterable), iterable) format(type(iterable), iterable)
except: except Exception as e:
logger.debug(f'Iterable {self.iterable} expansion error: {e}')
iterable = Request.expand_value_from_context(self.iterable, **context) iterable = Request.expand_value_from_context(self.iterable, **context)
response = Response() response = Response()
@ -334,10 +334,10 @@ class WhileProcedure(LoopProcedure):
@staticmethod @staticmethod
def _get_context(**context): def _get_context(**context):
for (k, v) in context.items(): for (k, v) in context.items():
# noinspection PyBroadException
try: try:
context[k] = eval(v) context[k] = eval(v)
except: except Exception as e:
logger.debug(f'Evaluation error for {v}: {e}')
if isinstance(v, str): if isinstance(v, str):
# noinspection PyBroadException # noinspection PyBroadException
try: try:
@ -356,8 +356,8 @@ class WhileProcedure(LoopProcedure):
for k, v in context.items(): for k, v in context.items():
try: try:
exec('{}={}'.format(k, v)) exec('{}={}'.format(k, v))
except: except Exception as e:
pass logger.debug(f'Evaluation error: {k}={v}: {e}')
while True: while True:
condition_true = eval(self.condition) condition_true = eval(self.condition)
@ -386,8 +386,8 @@ class WhileProcedure(LoopProcedure):
for k, v in new_context.items(): for k, v in new_context.items():
try: try:
exec('{}={}'.format(k, v)) exec('{}={}'.format(k, v))
except: except Exception as e:
pass logger.debug(f'Evaluation error: {k}={v}: {e}')
return response return response
@ -453,7 +453,8 @@ class IfProcedure(Procedure):
for (k, v) in context.items(): for (k, v) in context.items():
try: try:
exec('{}={}'.format(k, v)) exec('{}={}'.format(k, v))
except: except Exception as e:
logger.debug(f'Evaluation error: {k}={v}: {e}')
if isinstance(v, str): if isinstance(v, str):
try: try:
exec('{}="{}"'.format(k, re.sub(r'(^|[^\\])"', '\1\\"', v))) exec('{}="{}"'.format(k, re.sub(r'(^|[^\\])"', '\1\\"', v)))

View File

@ -169,14 +169,6 @@ class UserManager:
""" """
session = self._get_db_session() session = self._get_db_session()
return session.query(User).join(UserSession).filter_by(session_token=session_token).first() return session.query(User).join(UserSession).filter_by(session_token=session_token).first()
if not user:
return None
return {
'user_id': user.user_id,
'username': user.username,
'created_at': user.created_at,
}
def generate_jwt_token(self, username: str, password: str, expires_at: Optional[datetime.datetime] = None) -> str: def generate_jwt_token(self, username: str, password: str, expires_at: Optional[datetime.datetime] = None) -> str:
""" """

Some files were not shown because too many files have changed in this diff Show More