Skip to content

Commit

Permalink
Call aiy.common.LED from led.py.
Browse files Browse the repository at this point in the history
The status-led service will now call into aiy.common.LED.

Also raise a ValueError when an unexpected state is passed to
aiy.common.LED.set_state.

Tested:
  Tried src/main.py and observed expected LED animations.
  • Loading branch information
enetor committed Jun 27, 2017
1 parent 73ab0e4 commit e4e7b7d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 105 deletions.
9 changes: 4 additions & 5 deletions src/aiy/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This library provides common drivers for the AIY projects.
Drivers in this module requires GPIO.setmode(GPIO.BCM).
"""
"""This library provides common drivers for the AIY projects."""

import itertools
import os
Expand Down Expand Up @@ -55,6 +52,7 @@ def __init__(self,
self.expected_value = polarity == GPIO.RISING
self.debounce_time = debounce_time

GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN, pull_up_down=pull_up_down)

self.callback = None
Expand Down Expand Up @@ -135,6 +133,7 @@ def __init__(self, channel):
self.state = None
self.sleep = 0

GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.OUT)
self.pwm = GPIO.PWM(channel, 100)

Expand Down Expand Up @@ -176,7 +175,7 @@ def _animate(self):
return
if state:
if not self._parse_state(state):
print('unsupported state: %d' % state)
raise ValueError('unsupported state: %d' % state)
if self.iterator:
self.pwm.ChangeDutyCycle(next(self.iterator))
time.sleep(self.sleep)
Expand Down
124 changes: 24 additions & 100 deletions src/led.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,131 +11,54 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Signal states on a LED"""

'''Signal states on a LED'''

import itertools
import logging
import os
import threading
import time

import aiy.common
import RPi.GPIO as GPIO

logger = logging.getLogger('led')
logger = logging.getLogger("led")

CONFIG_DIR = os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config')
CONFIG_DIR = os.getenv("XDG_CONFIG_HOME") or os.path.expanduser("~/.config")
CONFIG_FILES = [
'/etc/status-led.ini',
os.path.join(CONFIG_DIR, 'status-led.ini')
"/etc/status-led.ini",
os.path.join(CONFIG_DIR, "status-led.ini")
]


class LED:

"""Starts a background thread to show patterns with the LED."""

def __init__(self, channel):
self.animator = threading.Thread(target=self._animate)
self.channel = channel
self.iterator = None
self.running = False
self.state = None
self.sleep = 0

GPIO.setup(channel, GPIO.OUT)
self.pwm = GPIO.PWM(channel, 100)

def start(self):
self.pwm.start(0) # off by default
self.running = True
self.animator.start()

def stop(self):
self.running = False
self.animator.join()
self.pwm.stop()
GPIO.output(self.channel, GPIO.LOW)

def set_state(self, state):
self.state = state

def _animate(self):
# TODO(ensonic): refactor or add justification
# pylint: disable=too-many-branches
while self.running:
if self.state:
if self.state == 'on':
self.iterator = None
self.sleep = 0.0
self.pwm.ChangeDutyCycle(100)
elif self.state == 'off':
self.iterator = None
self.sleep = 0.0
self.pwm.ChangeDutyCycle(0)
elif self.state == 'blink':
self.iterator = itertools.cycle([0, 100])
self.sleep = 0.5
elif self.state == 'blink-3':
self.iterator = itertools.cycle([0, 100] * 3 + [0, 0])
self.sleep = 0.25
elif self.state == 'beacon':
self.iterator = itertools.cycle(
itertools.chain([30] * 100, [100] * 8, range(100, 30, -5)))
self.sleep = 0.05
elif self.state == 'beacon-dark':
self.iterator = itertools.cycle(
itertools.chain([0] * 100, range(0, 30, 3), range(30, 0, -3)))
self.sleep = 0.05
elif self.state == 'decay':
self.iterator = itertools.cycle(range(100, 0, -2))
self.sleep = 0.05
elif self.state == 'pulse-slow':
self.iterator = itertools.cycle(
itertools.chain(range(0, 100, 2), range(100, 0, -2)))
self.sleep = 0.1
elif self.state == 'pulse-quick':
self.iterator = itertools.cycle(
itertools.chain(range(0, 100, 5), range(100, 0, -5)))
self.sleep = 0.05
else:
logger.warning("unsupported state: %s", self.state)
self.state = None
if self.iterator:
self.pwm.ChangeDutyCycle(next(self.iterator))
time.sleep(self.sleep)
else:
time.sleep(1)


def main():
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)
format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s")

import configargparse
parser = configargparse.ArgParser(
default_config_files=CONFIG_FILES,
description="Status LED daemon")
parser.add_argument('-G', '--gpio-pin', default=25, type=int,
help='GPIO pin for the LED (default: 25)')
default_config_files=CONFIG_FILES, description="Status LED daemon")
parser.add_argument(
"-G",
"--gpio-pin",
default=25,
type=int,
help="GPIO pin for the LED (default: 25)")
args = parser.parse_args()

led = None
state_map = {
"starting": "pulse-quick",
"ready": "beacon-dark",
"listening": "on",
"thinking": "pulse-quick",
"stopping": "pulse-quick",
"power-off": "off",
"error": "blink-3",
"starting": aiy.common.LED.LED_PULSE_QUICK,
"ready": aiy.common.LED.LED_BEACON_DARK,
"listening": aiy.common.LED.LED_ON,
"thinking": aiy.common.LED.LED_PULSE_QUICK,
"stopping": aiy.common.LED.LED_PULSE_QUICK,
"power-off": aiy.common.LED.LED_OFF,
"error": aiy.common.LED.LED_BLINK_3,
}
try:
GPIO.setmode(GPIO.BCM)

led = LED(args.gpio_pin)
led = aiy.common.LED(args.gpio_pin)
led.start()
while True:
try:
Expand All @@ -156,5 +79,6 @@ def main():
led.stop()
GPIO.cleanup()

if __name__ == '__main__':

if __name__ == "__main__":
main()

0 comments on commit e4e7b7d

Please sign in to comment.