display_manager.py
Go to the documentation of this file.
1 # Copyright 2017 Mycroft AI Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 
16 """ DisplayManager
17 
18 This module provides basic "state" for the visual representation associated
19 with this Mycroft instance. The current states are:
20  ActiveSkill - The skill that last interacted with the display via the
21  Enclosure API.
22 
23 Currently, a wakeword sets the ActiveSkill to "wakeword", which will auto
24 clear after 10 seconds.
25 
26 A skill is set to Active when it matches an intent, outputs audio, or
27 changes the display via the EnclosureAPI()
28 
29 A skill is automatically cleared from Active two seconds after audio
30 output is spoken, or 2 seconds after resetting the display.
31 
32 So it is common to have '' as the active skill.
33 """
34 
35 import json
36 from threading import Thread, Timer
37 
38 import os
39 
40 from mycroft.messagebus.client.ws import WebsocketClient
41 from mycroft.util import get_ipc_directory
42 from mycroft.util.log import LOG
43 
44 
45 def _write_data(dictionary):
46  """ Writes the dictionary of state data to the IPC directory.
47 
48  Args:
49  dictionary (dict): information to place in the 'disp_info' file
50  """
51 
52  managerIPCDir = os.path.join(get_ipc_directory(), "managers")
53  # change read/write permissions based on if file exists or not
54  path = os.path.join(managerIPCDir, "disp_info")
55  permission = "r+" if os.path.isfile(path) else "w+"
56 
57  if permission == "w+" and os.path.isdir(managerIPCDir) is False:
58  os.makedirs(managerIPCDir)
59  os.chmod(managerIPCDir, 0o777)
60 
61  try:
62  with open(path, permission) as dispFile:
63 
64  # check if file is empty
65  if os.stat(str(dispFile.name)).st_size != 0:
66  data = json.load(dispFile)
67 
68  else:
69  data = {}
70  LOG.info("Display Manager is creating " + dispFile.name)
71 
72  for key in dictionary:
73  data[key] = dictionary[key]
74 
75  dispFile.seek(0)
76  dispFile.write(json.dumps(data))
77  dispFile.truncate()
78 
79  os.chmod(path, 0o777)
80 
81  except Exception as e:
82  LOG.error(e)
83  LOG.error("Error found in display manager file, deleting...")
84  os.remove(path)
85  _write_data(dictionary)
86 
87 
88 def _read_data():
89  """ Writes the dictionary of state data from the IPC directory.
90  Returns:
91  dict: loaded state information
92  """
93  managerIPCDir = os.path.join(get_ipc_directory(), "managers")
94 
95  path = os.path.join(managerIPCDir, "disp_info")
96  permission = "r" if os.path.isfile(path) else "w+"
97 
98  if permission == "w+" and os.path.isdir(managerIPCDir) is False:
99  os.makedirs(managerIPCDir)
100 
101  data = {}
102  try:
103  with open(path, permission) as dispFile:
104 
105  if os.stat(str(dispFile.name)).st_size != 0:
106  data = json.load(dispFile)
107 
108  except Exception as e:
109  LOG.error(e)
110  os.remove(path)
111  _read_data()
112 
113  return data
114 
115 
117  """ The Display manager handles the basic state of the display,
118  be it a mark-1 or a mark-2 or even a future Mark-3.
119  """
120  def __init__(self, name=None):
121  self.name = name or ""
122 
123  def set_active(self, skill_name=None):
124  """ Sets skill name as active in the display Manager
125  Args:
126  string: skill_name
127  """
128  name = skill_name if skill_name is not None else self.name
129  _write_data({"active_skill": name})
130 
131  def get_active(self):
132  """ Get the currenlty active skill from the display manager
133  Returns:
134  string: The active skill's name
135  """
136  data = _read_data()
137  active_skill = ""
138 
139  if "active_skill" in data:
140  active_skill = data["active_skill"]
141 
142  return active_skill
143 
144  def remove_active(self):
145  """ Clears the active skill """
146  LOG.debug("Removing active skill...")
147  _write_data({"active_skill": ""})
148 
149 
151  """ Connects the display manager to the messagebus """
152  LOG.info("Connecting display manager to messagebus")
153 
154  # Should remove needs to be an object so it can be referenced in functions
155  # [https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference]
156  display_manager = DisplayManager()
157  should_remove = [True]
158 
159  def check_flag(flag):
160  if flag[0] is True:
161  display_manager.remove_active()
162 
163  def set_delay(event=None):
164  should_remove[0] = True
165  Timer(2, check_flag, [should_remove]).start()
166 
167  def set_remove_flag(event=None):
168  should_remove[0] = False
169 
170  def connect():
171  bus.run_forever()
172 
173  def remove_wake_word():
174  data = _read_data()
175  if "active_skill" in data and data["active_skill"] == "wakeword":
176  display_manager.remove_active()
177 
178  def set_wakeword_skill(event=None):
179  display_manager.set_active("wakeword")
180  Timer(10, remove_wake_word).start()
181 
182  bus = WebsocketClient()
183  bus.on('recognizer_loop:audio_output_end', set_delay)
184  bus.on('recognizer_loop:audio_output_start', set_remove_flag)
185  bus.on('recognizer_loop:record_begin', set_wakeword_skill)
186 
187  event_thread = Thread(target=connect)
188  event_thread.setDaemon(True)
189  event_thread.start()
def get_ipc_directory(domain=None)
Definition: signal.py:25


mycroft_ros
Author(s):
autogenerated on Mon Apr 26 2021 02:35:40