Compare commits
10 Commits
71a3481560
...
e9abb5cb9a
Author | SHA1 | Date |
---|---|---|
Fabio Manganiello | e9abb5cb9a | |
Fabio Manganiello | b1cb7ef847 | |
Fabio Manganiello | 718e0434ba | |
Fabio Manganiello | 78bbe71be1 | |
Fabio Manganiello | 3743ee4f00 | |
Fabio Manganiello | 431dedf3eb | |
Fabio Manganiello | 0a4b22c12e | |
Fabio Manganiello | 714f853751 | |
Fabio Manganiello | a011de890b | |
Fabio Manganiello | 2b5596820b |
|
@ -299,7 +299,7 @@ autodoc_mock_imports = [
|
|||
'async_lru',
|
||||
'bleak',
|
||||
'bluetooth_numbers',
|
||||
'TheengsGateway',
|
||||
'TheengsDecoder',
|
||||
]
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><link rel="stylesheet" href="/fonts/poppins.css"><title>platypush</title><script defer="defer" type="module" src="/static/js/chunk-vendors.95bedba1.js"></script><script defer="defer" type="module" src="/static/js/app.027226cc.js"></script><link href="/static/css/chunk-vendors.0fcd36f0.css" rel="stylesheet"><link href="/static/css/app.aa0132dc.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.79dede0c.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.a7f221b9.js" nomodule></script></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><link rel="stylesheet" href="/fonts/poppins.css"><title>platypush</title><script defer="defer" type="module" src="/static/js/chunk-vendors.95bedba1.js"></script><script defer="defer" type="module" src="/static/js/app.d0179f42.js"></script><link href="/static/css/chunk-vendors.0fcd36f0.css" rel="stylesheet"><link href="/static/css/app.aa0132dc.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.79dede0c.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.d0b74440.js" nomodule></script></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -121,13 +121,19 @@ $label-width: 3em;
|
|||
|
||||
.range-labels {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
&.with-label {
|
||||
width: calc(100% - $label-width);
|
||||
}
|
||||
|
||||
.left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
@extend .pull-right;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Device.vue
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div class="entity device-container">
|
||||
<div class="head">
|
||||
<div class="col-1 icon">
|
||||
<EntityIcon
|
||||
:entity="value"
|
||||
:loading="loading"
|
||||
:error="error" />
|
||||
</div>
|
||||
|
||||
<div class="col-2 connector">
|
||||
<ToggleSwitch
|
||||
:value="value.connected"
|
||||
:disabled="loading"
|
||||
@input="connect"
|
||||
@click.stop />
|
||||
</div>
|
||||
|
||||
<div class="col-9 label">
|
||||
<div class="name" v-text="value.name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EntityMixin from "./EntityMixin"
|
||||
import EntityIcon from "./EntityIcon"
|
||||
import ToggleSwitch from "@/components/elements/ToggleSwitch"
|
||||
|
||||
export default {
|
||||
name: 'BluetoothDevice',
|
||||
components: {EntityIcon, ToggleSwitch},
|
||||
mixins: [EntityMixin],
|
||||
|
||||
methods: {
|
||||
async connect(event) {
|
||||
event.stopPropagation()
|
||||
this.$emit('loading', true)
|
||||
const method = (
|
||||
'bluetooth.' +
|
||||
(this.value.connected ? 'disconnect' : 'connect')
|
||||
)
|
||||
|
||||
try {
|
||||
await this.request(method, {
|
||||
device: this.value.address,
|
||||
})
|
||||
} finally {
|
||||
this.$emit('loading', false)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "common";
|
||||
|
||||
.device-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.connector {
|
||||
width: 4em;
|
||||
margin: 0.25em 0 -0.25em 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<div class="col-2 connector pull-right">
|
||||
<ToggleSwitch
|
||||
:value="parent.connected"
|
||||
:value="value.connected"
|
||||
:disabled="loading"
|
||||
@input="connect"
|
||||
@click.stop />
|
||||
|
@ -37,9 +37,13 @@ export default {
|
|||
async connect(event) {
|
||||
event.stopPropagation()
|
||||
this.$emit('loading', true)
|
||||
const method = (
|
||||
'bluetooth.' +
|
||||
(this.value.connected ? 'disconnect' : 'connect')
|
||||
)
|
||||
|
||||
try {
|
||||
await this.request('bluetooth.connect', {
|
||||
await this.request(method, {
|
||||
device: this.parent.address,
|
||||
service_uuid: this.uuid,
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
:error="error" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 label">
|
||||
<div class="col-11 label">
|
||||
<div class="name" v-text="value.name" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
</div>
|
||||
|
||||
<div class="col-s-4 col-m-3 buttons pull-right">
|
||||
<span class="value-percent"
|
||||
v-text="parsedValue"
|
||||
v-if="parsedValue != null" />
|
||||
<button @click.stop="collapsed = !collapsed">
|
||||
<i class="fas"
|
||||
:class="{'fa-angle-up': !collapsed, 'fa-angle-down': collapsed}" />
|
||||
</button>
|
||||
<span class="value-percent"
|
||||
v-text="parsedValue"
|
||||
v-if="parsedValue != null" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
:is="component"
|
||||
:value="value"
|
||||
:parent="parent"
|
||||
:children="computedChildren"
|
||||
:loading="loading"
|
||||
ref="instance"
|
||||
:error="error || value?.reachable == false"
|
||||
|
@ -30,6 +31,7 @@
|
|||
:parent="value"
|
||||
:loading="loading"
|
||||
:level="level + 1"
|
||||
@show-modal="$emit('show-modal', $event)"
|
||||
@input="$emit('input', entity)" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -44,7 +46,7 @@ import { bus } from "@/bus";
|
|||
export default {
|
||||
name: "Entity",
|
||||
mixins: [EntityMixin],
|
||||
emits: ['input', 'loading', 'update'],
|
||||
emits: ['input', 'loading', 'update', 'show-modal'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
@ -87,12 +89,19 @@ export default {
|
|||
},
|
||||
|
||||
onClick(event) {
|
||||
event.stopPropagation()
|
||||
|
||||
if (
|
||||
event.target.classList.contains('label') ||
|
||||
event.target.classList.contains('head')
|
||||
) {
|
||||
event.stopPropagation()
|
||||
// When clicking on the name or icon of the entity, stop the event
|
||||
// propagation and toggle the collapsed state instead.
|
||||
this.toggleCollapsed()
|
||||
} else {
|
||||
// Otherwise, propagate the event upwards as a request to show the
|
||||
// entity details modal.
|
||||
this.$emit('show-modal', this.value.id)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -210,6 +219,10 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.icon:hover {
|
||||
color: $hover-fg;
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
</div>
|
||||
|
||||
<div class="col-s-3 col-m-2 buttons pull-right">
|
||||
<span class="value"
|
||||
v-text="value.values[value.value] || value.value"
|
||||
v-if="value?.value != null" />
|
||||
<button @click.stop="collapsed = !collapsed" v-if="hasValues">
|
||||
<i class="fas"
|
||||
:class="{'fa-angle-up': !collapsed, 'fa-angle-down': collapsed}" />
|
||||
</button>
|
||||
<span class="value"
|
||||
v-text="value.values[value.value] || value.value"
|
||||
v-if="value?.value != null" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
:visible="modalVisible"
|
||||
:config-values="configValuesByParentId(modalEntityId)"
|
||||
@close="onEntityModal"
|
||||
@entity-update="modalEntityId = $event"
|
||||
v-if="modalEntityId && entities[modalEntityId]"
|
||||
/>
|
||||
|
||||
|
@ -48,11 +49,13 @@
|
|||
</div>
|
||||
|
||||
<div class="body">
|
||||
<div class="entity-frame" @click="onEntityModal(entity.id)"
|
||||
v-for="entity in group.entities" :key="entity.id">
|
||||
<div class="entity-frame"
|
||||
v-for="entity in group.entities"
|
||||
:key="entity.id">
|
||||
<Entity
|
||||
:value="entity"
|
||||
:children="childrenByParentId(entity.id)"
|
||||
@show-modal="onEntityModal($event)"
|
||||
@input="onEntityInput(entity)"
|
||||
:error="!!errorEntities[entity.id]"
|
||||
:loading="!!loadingEntities[entity.id]"
|
||||
|
|
|
@ -90,10 +90,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-for="value, attr in entity.data || {}" :key="attr">
|
||||
<div class="table-row" v-if="value != null">
|
||||
<div class="title" v-text="prettify(attr)" />
|
||||
<div class="value" v-text="'' + value" />
|
||||
<div class="table-row" v-if="entity.parent_id">
|
||||
<div class="title">Parent</div>
|
||||
<div class="value">
|
||||
<a href="#"
|
||||
@click="$emit('entity-update', entity.parent_id)"
|
||||
v-text="entity.parent_id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -107,18 +110,49 @@
|
|||
<div class="value" v-text="formatDateTime(entity.updated_at)" />
|
||||
</div>
|
||||
|
||||
<div class="table-row delete-entity-container">
|
||||
<div class="table-row delete-entity-container"
|
||||
@click="$refs.deleteConfirmDiag.show()">
|
||||
<div class="title">Delete Entity</div>
|
||||
<div class="value">
|
||||
<button @click="$refs.deleteConfirmDiag.show()">
|
||||
<button @click.stop="$refs.deleteConfirmDiag.show()">
|
||||
<i class="fas fa-trash" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="extra-info-container">
|
||||
<div class="title section-title" @click="extraInfoCollapsed = !extraInfoCollapsed">
|
||||
<div class="col-11">
|
||||
<i class="fas fa-circle-info" />
|
||||
Extra Info
|
||||
</div>
|
||||
|
||||
<div class="col-1 pull-right">
|
||||
<i class="fas"
|
||||
:class="{'fa-chevron-down': extraInfoCollapsed, 'fa-chevron-up': !extraInfoCollapsed}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="extra-info" v-if="!extraInfoCollapsed">
|
||||
<div v-for="value, attr in entity" :key="attr">
|
||||
<div class="table-row" v-if="value != null && specialFields.indexOf(attr) < 0">
|
||||
<div class="title" v-text="prettify(attr)" />
|
||||
<div class="value" v-text="stringify(value)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-for="value, attr in (entity.data || {})" :key="attr">
|
||||
<div class="table-row" v-if="value != null">
|
||||
<div class="title" v-text="prettify(attr)" />
|
||||
<div class="value" v-text="stringify(value)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-container"
|
||||
v-if="computedConfig.length">
|
||||
<div class="title"
|
||||
<div class="title section-title"
|
||||
@click="configCollapsed = !configCollapsed">
|
||||
<div class="col-11">
|
||||
<i class="fas fa-screwdriver-wrench" />
|
||||
|
@ -152,11 +186,27 @@ import Utils from "@/Utils";
|
|||
import Entity from "./Entity";
|
||||
import meta from './meta.json';
|
||||
|
||||
// These fields have a different rendering logic than the general-purpose one
|
||||
const specialFields = [
|
||||
'created_at',
|
||||
'data',
|
||||
'description',
|
||||
'external_id',
|
||||
'external_url',
|
||||
'id',
|
||||
'image_url',
|
||||
'meta',
|
||||
'name',
|
||||
'plugin',
|
||||
'updated_at',
|
||||
'parent_id',
|
||||
]
|
||||
|
||||
export default {
|
||||
name: "EntityModal",
|
||||
components: {Entity, Modal, EditButton, NameEditor, Icon, ConfirmDialog},
|
||||
mixins: [Utils],
|
||||
emits: ['input', 'loading'],
|
||||
emits: ['input', 'loading', 'entity-update'],
|
||||
props: {
|
||||
entity: {
|
||||
type: Object,
|
||||
|
@ -188,6 +238,8 @@ export default {
|
|||
editName: false,
|
||||
editIcon: false,
|
||||
configCollapsed: true,
|
||||
extraInfoCollapsed: true,
|
||||
specialFields: specialFields,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -257,6 +309,14 @@ export default {
|
|||
this.editIcon = false
|
||||
}
|
||||
},
|
||||
|
||||
stringify(value) {
|
||||
if (value == null)
|
||||
return ''
|
||||
if (Array.isArray(value) || typeof value === 'object')
|
||||
return JSON.stringify(value)
|
||||
return '' + value
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -306,26 +366,39 @@ export default {
|
|||
|
||||
.delete-entity-container {
|
||||
color: $error-fg;
|
||||
cursor: pointer;
|
||||
button {
|
||||
color: $error-fg;
|
||||
}
|
||||
}
|
||||
|
||||
.config-container {
|
||||
@mixin section-title {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
padding: 1em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.033em;
|
||||
border-top: $default-border;
|
||||
box-shadow: $border-shadow-bottom;
|
||||
|
||||
&:hover {
|
||||
background: $hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.config-container,
|
||||
.extra-info-container
|
||||
{
|
||||
margin: 0;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
padding: 1em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.033em;
|
||||
border-top: $default-border;
|
||||
box-shadow: $border-shadow-bottom;
|
||||
cursor: pointer;
|
||||
.section-title {
|
||||
@include section-title;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $hover-bg;
|
||||
}
|
||||
.config-container {
|
||||
.title {
|
||||
@include section-title;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
<div class="col-s-3 col-m-2 pull-right"
|
||||
v-if="value.value != null">
|
||||
<span class="value" v-text="value.value" />
|
||||
<span class="unit" v-text="value.unit"
|
||||
v-if="value.unit != null" />
|
||||
<span class="value" v-text="value.value" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -21,12 +21,10 @@
|
|||
}
|
||||
|
||||
.pull-right {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
direction: rtl;
|
||||
padding-right: 0.5em;
|
||||
|
||||
:deep(.power-switch) {
|
||||
@include pull-right;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,21 +150,26 @@ $widths: (
|
|||
}
|
||||
|
||||
.vertical-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.horizontal-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
@mixin pull-right {
|
||||
display: inline-flex;
|
||||
text-align: right;
|
||||
justify-content: right;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
text-align: right;
|
||||
float: right;
|
||||
justify-content: right;
|
||||
@include pull-right;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
|
|
|
@ -42,6 +42,10 @@ export default {
|
|||
if (typeof(a) !== 'object' || typeof(b) !== 'object')
|
||||
return false
|
||||
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null
|
||||
}
|
||||
|
||||
for (const p of Object.keys(a || {})) {
|
||||
switch(typeof(a[p])) {
|
||||
case 'object':
|
||||
|
|
|
@ -193,7 +193,7 @@ if 'entity' not in Base.metadata:
|
|||
# standard multiple inheritance with an SQLAlchemy ORM class)
|
||||
Entity.__bases__ = Entity.__bases__ + (JSONAble,)
|
||||
|
||||
EntitySavedCallback = Callable[[Entity], None]
|
||||
EntitySavedCallback = Callable[[Entity], Any]
|
||||
"""
|
||||
Type for the callback functions that should be called when an entity is saved
|
||||
on the database.
|
||||
|
|
|
@ -7,8 +7,7 @@ from bleak.backends.device import BLEDevice
|
|||
from bleak.backends.scanner import AdvertisementData
|
||||
from bluetooth_numbers import company
|
||||
|
||||
# pylint: disable=no-name-in-module
|
||||
from TheengsGateway._decoder import decodeBLE, getAttribute, getProperties
|
||||
from TheengsDecoder import decodeBLE, getAttribute, getProperties
|
||||
|
||||
from platypush.entities import Entity
|
||||
from platypush.entities.batteries import Battery
|
||||
|
|
|
@ -9,6 +9,7 @@ from typing import (
|
|||
Final,
|
||||
List,
|
||||
Optional,
|
||||
Set,
|
||||
Union,
|
||||
Type,
|
||||
)
|
||||
|
@ -50,7 +51,7 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
|
||||
* **bleak** (``pip install bleak``)
|
||||
* **bluetooth-numbers** (``pip install bluetooth-numbers``)
|
||||
* **TheengsGateway** (``pip install git+https://github.com/theengs/gateway``)
|
||||
* **TheengsDecoder** (``pip install TheengsDecoder``)
|
||||
* **pybluez** (``pip install git+https://github.com/pybluez/pybluez``)
|
||||
* **pyobex** (``pip install git+https://github.com/BlackLight/PyOBEX``)
|
||||
|
||||
|
@ -76,6 +77,16 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
_default_scan_duration: Final[float] = 10.0
|
||||
""" Default duration of a discovery session (in seconds) """
|
||||
|
||||
_default_excluded_manufacturers = {
|
||||
'Apple, Inc.',
|
||||
'Google',
|
||||
'Microsoft',
|
||||
}
|
||||
"""
|
||||
Exclude beacons from these device manufacturers by default (main offenders
|
||||
when it comes to Bluetooth device space pollution).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
interface: Optional[str] = None,
|
||||
|
@ -83,6 +94,7 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
service_uuids: Optional[Collection[RawServiceClass]] = None,
|
||||
scan_paused_on_start: bool = False,
|
||||
poll_interval: float = _default_scan_duration,
|
||||
excluded_manufacturers: Optional[Collection[str]] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
|
@ -95,7 +107,14 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
:param scan_paused_on_start: If ``True``, the plugin will not the
|
||||
scanning thread until :meth:`.scan_resume` is called (default:
|
||||
``False``).
|
||||
|
||||
:param excluded_manufacturers: Exclude beacons from these device
|
||||
manufacturers. The default list includes Apple, Google and
|
||||
Microsoft, who are among the main offenders when it comes to
|
||||
Bluetooth device address space pollution. Set this value to an
|
||||
empty list if you want to get all beacons (e.g. because you need to
|
||||
communicate with Apple AirTags or Google devices over Bluetooth),
|
||||
but be warned that the list of discovered Bluetooth devices may
|
||||
dramatically increase over time.
|
||||
"""
|
||||
kwargs['poll_interval'] = poll_interval
|
||||
super().__init__(**kwargs)
|
||||
|
@ -119,6 +138,10 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
"""
|
||||
Cache of the devices discovered by the plugin.
|
||||
"""
|
||||
self._excluded_manufacturers: Set[str] = set(excluded_manufacturers or [])
|
||||
"""
|
||||
Set of manufacturer strings whose associated devices should be ignored.
|
||||
"""
|
||||
|
||||
self._managers: Dict[Type[BaseBluetoothManager], BaseBluetoothManager] = {}
|
||||
"""
|
||||
|
@ -553,7 +576,8 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
|
|||
continue
|
||||
|
||||
device = self._device_cache.add(device)
|
||||
self.publish_entities([device], callback=self._device_cache.add)
|
||||
if device.manufacturer not in self._excluded_manufacturers:
|
||||
self.publish_entities([device], callback=self._device_cache.add)
|
||||
finally:
|
||||
self.stop()
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ manifest:
|
|||
pip:
|
||||
- bleak
|
||||
- bluetooth-numbers
|
||||
- TheengsDecoder
|
||||
- git+https://github.com/pybluez/pybluez
|
||||
- git+https://github.com/theengs/gateway
|
||||
- git+https://github.com/BlackLight/PyOBEX
|
||||
package: platypush.plugins.bluetooth
|
||||
type: plugin
|
||||
|
|
4
setup.py
4
setup.py
|
@ -17,7 +17,7 @@ def readfile(fname):
|
|||
def pkg_files(dir):
|
||||
paths = []
|
||||
# noinspection PyShadowingNames
|
||||
for (path, _, files) in os.walk(dir):
|
||||
for path, _, files in os.walk(dir):
|
||||
for file in files:
|
||||
paths.append(os.path.join('..', path, file))
|
||||
return paths
|
||||
|
@ -177,9 +177,9 @@ setup(
|
|||
'bluetooth': [
|
||||
'bleak',
|
||||
'bluetooth-numbers',
|
||||
'TheengsDecoder',
|
||||
'pybluez @ https://github.com/pybluez/pybluez/tarball/master',
|
||||
'PyOBEX @ https://github.com/BlackLight/PyOBEX/tarball/master',
|
||||
'TheengsGateway @ https://github.com/theengs/gateway/tarball/development',
|
||||
],
|
||||
# Support for TP-Link devices
|
||||
'tplink': ['pyHS100'],
|
||||
|
|
Loading…
Reference in New Issue