Merge branch 'dev' into patch-1
commit
5725359f16
23
dev_setup.sh
23
dev_setup.sh
|
@ -257,6 +257,10 @@ function os_is() {
|
||||||
[[ $(grep "^ID=" /etc/os-release | awk -F'=' '/^ID/ {print $2}' | sed 's/\"//g') == $1 ]]
|
[[ $(grep "^ID=" /etc/os-release | awk -F'=' '/^ID/ {print $2}' | sed 's/\"//g') == $1 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function os_is_like() {
|
||||||
|
[[ $(grep "^ID_LIKE=" /etc/os-release | awk -F'=' '/^ID_LIKE/ {print $2}' | sed 's/\"//g') == $1 ]]
|
||||||
|
}
|
||||||
|
|
||||||
function redhat_common_install() {
|
function redhat_common_install() {
|
||||||
$SUDO yum install -y cmake gcc-c++ git python34 python34-devel libtool libffi-devel openssl-devel autoconf automake bison swig portaudio-devel mpg123 flac curl libicu-devel python34-pkgconfig libjpeg-devel fann-devel python34-libs pulseaudio
|
$SUDO yum install -y cmake gcc-c++ git python34 python34-devel libtool libffi-devel openssl-devel autoconf automake bison swig portaudio-devel mpg123 flac curl libicu-devel python34-pkgconfig libjpeg-devel fann-devel python34-libs pulseaudio
|
||||||
git clone https://github.com/libfann/fann.git
|
git clone https://github.com/libfann/fann.git
|
||||||
|
@ -273,24 +277,33 @@ function install_deps() {
|
||||||
echo 'Installing packages...'
|
echo 'Installing packages...'
|
||||||
if found_exe zypper ; then
|
if found_exe zypper ; then
|
||||||
# OpenSUSE
|
# OpenSUSE
|
||||||
|
echo ${GREEN} Installing packages for OpenSUSE...${RESET}
|
||||||
$SUDO zypper install -y git python3 python3-devel libtool libffi-devel libopenssl-devel autoconf automake bison swig portaudio-devel mpg123 flac curl libicu-devel pkg-config libjpeg-devel libfann-devel python3-curses pulseaudio
|
$SUDO zypper install -y git python3 python3-devel libtool libffi-devel libopenssl-devel autoconf automake bison swig portaudio-devel mpg123 flac curl libicu-devel pkg-config libjpeg-devel libfann-devel python3-curses pulseaudio
|
||||||
$SUDO zypper install -y -t pattern devel_C_C++
|
$SUDO zypper install -y -t pattern devel_C_C++
|
||||||
elif found_exe yum && os_is centos ; then
|
elif found_exe yum && os_is centos ; then
|
||||||
# CentOS
|
# CentOS
|
||||||
|
echo ${GREEN} Installing packages for Centos...${RESET}
|
||||||
$SUDO yum install epel-release
|
$SUDO yum install epel-release
|
||||||
redhat_common_install
|
redhat_common_install
|
||||||
elif found_exe yum && os_is rhel ; then
|
elif found_exe yum && os_is rhel ; then
|
||||||
# Redhat Enterprise Linux
|
# Redhat Enterprise Linux
|
||||||
|
echo ${GREEN} Installing packages for Red Hat...${RESET}
|
||||||
$SUDO yum install -y wget
|
$SUDO yum install -y wget
|
||||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||||
$SUDO yum install -y epel-release-latest-7.noarch.rpm
|
$SUDO yum install -y epel-release-latest-7.noarch.rpm
|
||||||
rm epel-release-latest-7.noarch.rpm
|
rm epel-release-latest-7.noarch.rpm
|
||||||
redhat_common_install
|
redhat_common_install
|
||||||
elif found_exe apt-get ; then
|
elif os_is_like debian ; then
|
||||||
# Debian / Ubuntu
|
# Debian / Ubuntu
|
||||||
|
echo ${GREEN} Installing packages for Debian/Ubuntu...${RESET}
|
||||||
$SUDO apt-get install -y git python3 python3-dev python-setuptools python-gobject-2-dev libtool libffi-dev libssl-dev autoconf automake bison swig libglib2.0-dev portaudio19-dev mpg123 screen flac curl libicu-dev pkg-config automake libjpeg-dev libfann-dev build-essential jq
|
$SUDO apt-get install -y git python3 python3-dev python-setuptools python-gobject-2-dev libtool libffi-dev libssl-dev autoconf automake bison swig libglib2.0-dev portaudio19-dev mpg123 screen flac curl libicu-dev pkg-config automake libjpeg-dev libfann-dev build-essential jq
|
||||||
|
elif os_is_like fedora ; then
|
||||||
|
echo ${GREEN} Installing packages for Fedora...${RESET}
|
||||||
|
# Fedora
|
||||||
|
$SUDO dnf install -y git python3 python3-devel python3-pip python3-setuptools python3-virtualenv pygobject3-devel libtool libffi-devel openssl-devel autoconf bison swig glib2-devel portaudio-devel mpg123 mpg123-plugins-pulseaudio screen curl pkgconfig libicu-devel automake libjpeg-turbo-devel fann-devel gcc-c++ redhat-rpm-config jq
|
||||||
elif found_exe pacman; then
|
elif found_exe pacman; then
|
||||||
# Arch Linux
|
# Arch Linux
|
||||||
|
echo ${GREEN} Installing packages for Arch...${RESET}
|
||||||
$SUDO pacman -S --needed --noconfirm git python python-pip python-setuptools python-virtualenv python-gobject python-virtualenvwrapper libffi swig portaudio mpg123 screen flac curl icu libjpeg-turbo base-devel jq pulseaudio pulseaudio-alsa
|
$SUDO pacman -S --needed --noconfirm git python python-pip python-setuptools python-virtualenv python-gobject python-virtualenvwrapper libffi swig portaudio mpg123 screen flac curl icu libjpeg-turbo base-devel jq pulseaudio pulseaudio-alsa
|
||||||
pacman -Qs '^fann$' &> /dev/null || (
|
pacman -Qs '^fann$' &> /dev/null || (
|
||||||
git clone https://aur.archlinux.org/fann.git
|
git clone https://aur.archlinux.org/fann.git
|
||||||
|
@ -299,12 +312,10 @@ function install_deps() {
|
||||||
cd ..
|
cd ..
|
||||||
rm -rf fann
|
rm -rf fann
|
||||||
)
|
)
|
||||||
elif found_exe dnf ; then
|
|
||||||
# Fedora
|
|
||||||
$SUDO dnf install -y git python3 python3-devel python3-pip python3-setuptools python3-virtualenv pygobject3-devel libtool libffi-devel openssl-devel autoconf bison swig glib2-devel portaudio-devel mpg123 mpg123-plugins-pulseaudio screen curl pkgconfig libicu-devel automake libjpeg-turbo-devel fann-devel gcc-c++ redhat-rpm-config jq
|
|
||||||
else
|
else
|
||||||
echo -e "\n${GREEN}Could not find package manager
|
echo
|
||||||
${GREEN}Make sure to manually install:$BLUE git python 2 python-setuptools python-virtualenv pygobject virtualenvwrapper libtool libffi openssl autoconf bison swig glib2.0 portaudio19 mpg123 flac curl fann g++\n$RESET"
|
echo -e "${YELLOW}Could not find package manager
|
||||||
|
${YELLOW}Make sure to manually install:$BLUE git python3 python-setuptools python-venv pygobject libtool libffi libjpg openssl autoconf bison swig glib2.0 portaudio19 mpg123 flac curl fann g++ jq\n$RESET"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ from mycroft.lock import Lock as PIDLock # Create/Support PID locking file
|
||||||
from mycroft.messagebus.client.ws import WebsocketClient
|
from mycroft.messagebus.client.ws import WebsocketClient
|
||||||
from mycroft.messagebus.message import Message
|
from mycroft.messagebus.message import Message
|
||||||
from mycroft.util import create_daemon, wait_for_exit_signal, \
|
from mycroft.util import create_daemon, wait_for_exit_signal, \
|
||||||
reset_sigint_handler
|
reset_sigint_handler, create_echo_function
|
||||||
from mycroft.util.log import LOG
|
from mycroft.util.log import LOG
|
||||||
|
|
||||||
bus = None # Mycroft messagebus connection
|
bus = None # Mycroft messagebus connection
|
||||||
|
@ -175,6 +175,7 @@ def main():
|
||||||
bus.on('recognizer_loop:audio_output_start', handle_audio_start)
|
bus.on('recognizer_loop:audio_output_start', handle_audio_start)
|
||||||
bus.on('recognizer_loop:audio_output_end', handle_audio_end)
|
bus.on('recognizer_loop:audio_output_end', handle_audio_end)
|
||||||
bus.on('mycroft.stop', handle_stop)
|
bus.on('mycroft.stop', handle_stop)
|
||||||
|
bus.on('message', create_echo_function('VOICE'))
|
||||||
|
|
||||||
create_daemon(bus.run_forever)
|
create_daemon(bus.run_forever)
|
||||||
create_daemon(loop.run)
|
create_daemon(loop.run)
|
||||||
|
|
|
@ -889,11 +889,15 @@ for s in help_struct:
|
||||||
help_longest = max(help_longest, len(ent[0]))
|
help_longest = max(help_longest, len(ent[0]))
|
||||||
|
|
||||||
|
|
||||||
|
HEADER_SIZE = 2
|
||||||
|
HEADER_FOOTER_SIZE = 4
|
||||||
|
|
||||||
|
|
||||||
def num_help_pages():
|
def num_help_pages():
|
||||||
lines = 0
|
lines = 0
|
||||||
for section in help_struct:
|
for section in help_struct:
|
||||||
lines += 2 + len(section[1])
|
lines += 3 + len(section[1])
|
||||||
return ceil(lines / (curses.LINES - 4))
|
return ceil(lines / (curses.LINES - HEADER_FOOTER_SIZE))
|
||||||
|
|
||||||
|
|
||||||
def do_draw_help(scr):
|
def do_draw_help(scr):
|
||||||
|
@ -914,11 +918,12 @@ def do_draw_help(scr):
|
||||||
|
|
||||||
scr.erase()
|
scr.erase()
|
||||||
render_header()
|
render_header()
|
||||||
y = 2
|
y = HEADER_SIZE
|
||||||
page = subscreen + 1
|
page = subscreen + 1
|
||||||
|
|
||||||
first = subscreen * (curses.LINES - 7) # account for header
|
# Find first and last taking into account the header and footer
|
||||||
last = first + (curses.LINES - 7) # account for header/footer
|
first = subscreen * (curses.LINES - HEADER_FOOTER_SIZE)
|
||||||
|
last = first + (curses.LINES - HEADER_FOOTER_SIZE)
|
||||||
i = 0
|
i = 0
|
||||||
for section in help_struct:
|
for section in help_struct:
|
||||||
y = render_help(section[0], y, i, first, last, CLR_HEADING)
|
y = render_help(section[0], y, i, first, last, CLR_HEADING)
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
# BE WARNED THAT THE CLASSES, FUNCTIONS, ETC MAY CHANGE WITHOUT WARNING.
|
# BE WARNED THAT THE CLASSES, FUNCTIONS, ETC MAY CHANGE WITHOUT WARNING.
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from contextlib import contextmanager
|
||||||
from enum import Enum, unique
|
from enum import Enum, unique
|
||||||
from functools import total_ordering
|
from functools import total_ordering, wraps
|
||||||
from itertools import count
|
from itertools import count
|
||||||
|
|
||||||
from mycroft import MycroftSkill
|
from mycroft import MycroftSkill
|
||||||
|
@ -29,6 +30,7 @@ from mycroft.messagebus.message import Message
|
||||||
|
|
||||||
ENTITY = "ENTITY"
|
ENTITY = "ENTITY"
|
||||||
SCENE = "SCENE"
|
SCENE = "SCENE"
|
||||||
|
IOT_REQUEST_ID = "iot_request_id" # TODO make the id a property of the request
|
||||||
|
|
||||||
|
|
||||||
_counter = count()
|
_counter = count()
|
||||||
|
@ -57,8 +59,14 @@ class _BusKeys():
|
||||||
RUN = BASE + ":run." # Will have skill_id appened
|
RUN = BASE + ":run." # Will have skill_id appened
|
||||||
REGISTER = BASE + "register"
|
REGISTER = BASE + "register"
|
||||||
CALL_FOR_REGISTRATION = REGISTER + ".request"
|
CALL_FOR_REGISTRATION = REGISTER + ".request"
|
||||||
|
SPEAK = BASE + ":speak"
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
# When adding a new Thing, Attribute, etc, be sure to also add the #
|
||||||
|
# corresponding voc files to the skill-iot-control. #
|
||||||
|
####################################################################
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class Thing(Enum):
|
class Thing(Enum):
|
||||||
"""
|
"""
|
||||||
|
@ -81,13 +89,35 @@ class Thing(Enum):
|
||||||
class Attribute(Enum):
|
class Attribute(Enum):
|
||||||
"""
|
"""
|
||||||
This class represents 'Attributes' of 'Things'.
|
This class represents 'Attributes' of 'Things'.
|
||||||
|
|
||||||
This may also grow to encompass states, e.g.
|
|
||||||
'locked' or 'unlocked'.
|
|
||||||
"""
|
"""
|
||||||
BRIGHTNESS = auto()
|
BRIGHTNESS = auto()
|
||||||
COLOR = auto()
|
COLOR = auto()
|
||||||
COLOR_TEMPERATURE = auto()
|
COLOR_TEMPERATURE = auto()
|
||||||
|
TEMPERATURE = auto()
|
||||||
|
|
||||||
|
|
||||||
|
@unique
|
||||||
|
class State(Enum):
|
||||||
|
"""
|
||||||
|
This class represents 'States' of 'Things'.
|
||||||
|
|
||||||
|
These are generally intended to handle binary
|
||||||
|
queries, such as "is the door locked?" or
|
||||||
|
"is the heat on?" where 'locked' and 'on'
|
||||||
|
are the state values. The special value
|
||||||
|
'STATE' can be used for more general queries
|
||||||
|
capable of providing more detailed in formation,
|
||||||
|
for example, "what is the state of the lamp?"
|
||||||
|
could produce state information that includes
|
||||||
|
brightness or color.
|
||||||
|
"""
|
||||||
|
STATE = auto()
|
||||||
|
POWERED = auto()
|
||||||
|
UNPOWERED = auto()
|
||||||
|
LOCKED = auto()
|
||||||
|
UNLOCKED = auto()
|
||||||
|
OCCUPIED = auto()
|
||||||
|
UNOCCUPIED = auto()
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
|
@ -106,6 +136,11 @@ class Action(Enum):
|
||||||
INCREASE = auto()
|
INCREASE = auto()
|
||||||
DECREASE = auto()
|
DECREASE = auto()
|
||||||
TRIGGER = auto()
|
TRIGGER = auto()
|
||||||
|
BINARY_QUERY = auto() # yes/no answer
|
||||||
|
INFORMATION_QUERY = auto() # detailed answer
|
||||||
|
LOCATE = auto()
|
||||||
|
LOCK = auto()
|
||||||
|
UNLOCK = auto()
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
|
@ -135,12 +170,14 @@ class IoTRequestVersion(Enum):
|
||||||
|
|
||||||
V1 = {'action', 'thing', 'attribute', 'entity', 'scene'}
|
V1 = {'action', 'thing', 'attribute', 'entity', 'scene'}
|
||||||
V2 = V1 | {'value'}
|
V2 = V1 | {'value'}
|
||||||
|
V3 = V2 | {'state'}
|
||||||
"""
|
"""
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return self.name < other.name
|
return self.name < other.name
|
||||||
|
|
||||||
V1 = {'action', 'thing', 'attribute', 'entity', 'scene'}
|
V1 = {'action', 'thing', 'attribute', 'entity', 'scene'}
|
||||||
V2 = V1 | {'value'}
|
V2 = V1 | {'value'}
|
||||||
|
V3 = V2 | {'state'}
|
||||||
|
|
||||||
|
|
||||||
class IoTRequest():
|
class IoTRequest():
|
||||||
|
@ -151,11 +188,13 @@ class IoTRequest():
|
||||||
a user's request. The information is supplied as properties
|
a user's request. The information is supplied as properties
|
||||||
on the request. At present, those properties are:
|
on the request. At present, those properties are:
|
||||||
|
|
||||||
action (see the Action enum above)
|
action (see the Action enum)
|
||||||
thing (see the Thing enum above)
|
thing (see the Thing enum)
|
||||||
|
state (see the State enum)
|
||||||
|
attribute (see the Attribute enum)
|
||||||
|
value
|
||||||
entity
|
entity
|
||||||
scene
|
scene
|
||||||
value
|
|
||||||
|
|
||||||
The 'action' is mandatory, and will always be not None. The
|
The 'action' is mandatory, and will always be not None. The
|
||||||
other fields may be None.
|
other fields may be None.
|
||||||
|
@ -186,7 +225,8 @@ class IoTRequest():
|
||||||
attribute: Attribute = None,
|
attribute: Attribute = None,
|
||||||
entity: str = None,
|
entity: str = None,
|
||||||
scene: str = None,
|
scene: str = None,
|
||||||
value: int = None):
|
value: int = None,
|
||||||
|
state: State = None):
|
||||||
|
|
||||||
if not thing and not entity and not scene:
|
if not thing and not entity and not scene:
|
||||||
raise Exception("At least one of thing,"
|
raise Exception("At least one of thing,"
|
||||||
|
@ -198,6 +238,7 @@ class IoTRequest():
|
||||||
self.entity = entity
|
self.entity = entity
|
||||||
self.scene = scene
|
self.scene = scene
|
||||||
self.value = value
|
self.value = value
|
||||||
|
self.state = state
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
template = ('IoTRequest('
|
template = ('IoTRequest('
|
||||||
|
@ -206,19 +247,26 @@ class IoTRequest():
|
||||||
' attribute={attribute},'
|
' attribute={attribute},'
|
||||||
' entity={entity},'
|
' entity={entity},'
|
||||||
' scene={scene},'
|
' scene={scene},'
|
||||||
' value={value}'
|
' value={value},'
|
||||||
|
' state={state}'
|
||||||
')')
|
')')
|
||||||
|
entity = '"{}"'.format(self.entity) if self.entity else None
|
||||||
|
scene = '"{}"'.format(self.scene) if self.scene else None
|
||||||
|
value = '"{}"'.format(self.value) if self.value is not None else None
|
||||||
return template.format(
|
return template.format(
|
||||||
action=self.action,
|
action=self.action,
|
||||||
thing=self.thing,
|
thing=self.thing,
|
||||||
attribute=self.attribute,
|
attribute=self.attribute,
|
||||||
entity='"{}"'.format(self.entity) if self.entity else None,
|
entity=entity,
|
||||||
scene='"{}"'.format(self.scene) if self.scene else None,
|
scene=scene,
|
||||||
value='"{}"'.format(self.value) if self.value is not None else None
|
value=value,
|
||||||
|
state=self.state
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self):
|
def version(self):
|
||||||
|
if self.state is not None:
|
||||||
|
return IoTRequestVersion.V3
|
||||||
if self.value is not None:
|
if self.value is not None:
|
||||||
return IoTRequestVersion.V2
|
return IoTRequestVersion.V2
|
||||||
return IoTRequestVersion.V1
|
return IoTRequestVersion.V1
|
||||||
|
@ -230,7 +278,8 @@ class IoTRequest():
|
||||||
'attribute': self.attribute.name if self.attribute else None,
|
'attribute': self.attribute.name if self.attribute else None,
|
||||||
'entity': self.entity,
|
'entity': self.entity,
|
||||||
'scene': self.scene,
|
'scene': self.scene,
|
||||||
'value': self.value
|
'value': self.value,
|
||||||
|
'state': self.state.name if self.state else None
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -241,10 +290,39 @@ class IoTRequest():
|
||||||
data['thing'] = Thing[data['thing']]
|
data['thing'] = Thing[data['thing']]
|
||||||
if data.get('attribute') not in (None, ''):
|
if data.get('attribute') not in (None, ''):
|
||||||
data['attribute'] = Attribute[data['attribute']]
|
data['attribute'] = Attribute[data['attribute']]
|
||||||
|
if data.get('state') not in (None, ''):
|
||||||
|
data['state'] = State[data['state']]
|
||||||
|
|
||||||
return cls(**data)
|
return cls(**data)
|
||||||
|
|
||||||
|
|
||||||
|
def _track_request(func):
|
||||||
|
"""
|
||||||
|
Used within the CommonIoT skill to track IoT requests.
|
||||||
|
|
||||||
|
The primary purpose of tracking the reqeust is determining
|
||||||
|
if the skill is currently handling an IoT request, or is
|
||||||
|
running a standard intent. While running IoT requests, certain
|
||||||
|
methods defined on MycroftSkill should behave differently than
|
||||||
|
under normal circumstances. In particular, speech related methods
|
||||||
|
should not actually trigger speech, but instead pass the message
|
||||||
|
to the IoT control skill, which will handle deconfliction (in the
|
||||||
|
event multiple skills want to respond verbally to the same request).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
func: Callable
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Callable
|
||||||
|
|
||||||
|
"""
|
||||||
|
@wraps(func)
|
||||||
|
def tracking_function(self, message: Message):
|
||||||
|
with self._current_request(message.data.get(IOT_REQUEST_ID)):
|
||||||
|
func(self, message)
|
||||||
|
return tracking_function
|
||||||
|
|
||||||
|
|
||||||
class CommonIoTSkill(MycroftSkill, ABC):
|
class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
"""
|
"""
|
||||||
Skills that want to work with the CommonIoT system should
|
Skills that want to work with the CommonIoT system should
|
||||||
|
@ -270,6 +348,11 @@ class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
step on each other.
|
step on each other.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@wraps(MycroftSkill.__init__)
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self._current_iot_request = None
|
||||||
|
|
||||||
def bind(self, bus):
|
def bind(self, bus):
|
||||||
"""
|
"""
|
||||||
Overrides MycroftSkill.bind.
|
Overrides MycroftSkill.bind.
|
||||||
|
@ -277,6 +360,9 @@ class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
This is called automatically during setup, and
|
This is called automatically during setup, and
|
||||||
need not otherwise be used.
|
need not otherwise be used.
|
||||||
|
|
||||||
|
Subclasses that override this method must call this
|
||||||
|
via super in their implementation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bus:
|
bus:
|
||||||
"""
|
"""
|
||||||
|
@ -287,6 +373,17 @@ class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
self.add_event(_BusKeys.CALL_FOR_REGISTRATION,
|
self.add_event(_BusKeys.CALL_FOR_REGISTRATION,
|
||||||
self._handle_call_for_registration)
|
self._handle_call_for_registration)
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def _current_request(self, id: str):
|
||||||
|
# Multiple simultaneous requests may interfere with each other as they
|
||||||
|
# would overwrite this value, however, this seems unlikely to cause
|
||||||
|
# any real world issues and tracking multiple requests seems as
|
||||||
|
# likely to cause issues as to solve them.
|
||||||
|
self._current_iot_request = id
|
||||||
|
yield id
|
||||||
|
self._current_iot_request = None
|
||||||
|
|
||||||
|
@_track_request
|
||||||
def _handle_trigger(self, message: Message):
|
def _handle_trigger(self, message: Message):
|
||||||
"""
|
"""
|
||||||
Given a message, determines if this skill can
|
Given a message, determines if this skill can
|
||||||
|
@ -308,6 +405,7 @@ class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
"callback_data": callback_data})
|
"callback_data": callback_data})
|
||||||
self.bus.emit(message.response(data))
|
self.bus.emit(message.response(data))
|
||||||
|
|
||||||
|
@_track_request
|
||||||
def _run_request(self, message: Message):
|
def _run_request(self, message: Message):
|
||||||
"""
|
"""
|
||||||
Given a message, extracts the IoTRequest and
|
Given a message, extracts the IoTRequest and
|
||||||
|
@ -321,6 +419,18 @@ class CommonIoTSkill(MycroftSkill, ABC):
|
||||||
callback_data = message.data["callback_data"]
|
callback_data = message.data["callback_data"]
|
||||||
self.run_request(request, callback_data)
|
self.run_request(request, callback_data)
|
||||||
|
|
||||||
|
def speak(self, utterance, *args, **kwargs):
|
||||||
|
if self._current_iot_request:
|
||||||
|
self.bus.emit(Message(_BusKeys.SPEAK,
|
||||||
|
data={"skill_id": self.skill_id,
|
||||||
|
IOT_REQUEST_ID:
|
||||||
|
self._current_iot_request,
|
||||||
|
"speak_args": args,
|
||||||
|
"speak_kwargs": kwargs,
|
||||||
|
"speak": utterance}))
|
||||||
|
else:
|
||||||
|
super().speak(utterance, *args, **kwargs)
|
||||||
|
|
||||||
def _handle_call_for_registration(self, _: Message):
|
def _handle_call_for_registration(self, _: Message):
|
||||||
"""
|
"""
|
||||||
Register this skill's scenes and entities when requested.
|
Register this skill's scenes and entities when requested.
|
||||||
|
|
|
@ -457,7 +457,8 @@ class SkillTest(object):
|
||||||
|
|
||||||
|
|
||||||
# Messages that should not print debug info
|
# Messages that should not print debug info
|
||||||
HIDDEN_MESSAGES = ['skill.converse.request', 'skill.converse.response']
|
HIDDEN_MESSAGES = ['skill.converse.request', 'skill.converse.response',
|
||||||
|
'gui.page.show', 'gui.value.set']
|
||||||
|
|
||||||
|
|
||||||
def load_dialog_list(skill, dialog):
|
def load_dialog_list(skill, dialog):
|
||||||
|
|
Loading…
Reference in New Issue