196 lines
6.8 KiB
Python
196 lines
6.8 KiB
Python
# Copyright (c) 2016 Anki, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License in the file LICENSE.txt or at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# 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.
|
|
|
|
'''Helper routines for dealing with Cozmo's lights and colors.'''
|
|
|
|
# __all__ should order by constants, event classes, other classes, functions.
|
|
__all__ = ['green', 'red', 'blue', 'white', 'off',
|
|
'green_light', 'red_light', 'blue_light', 'white_light', 'off_light',
|
|
'Color', 'Light']
|
|
|
|
import copy
|
|
|
|
from . import logger
|
|
|
|
|
|
class Color:
|
|
'''A Color to be used with a Light.
|
|
|
|
Either int_color or rgb may be used to specify the actual color.
|
|
Any alpha components (from int_color) are ignored - all colors are fully opaque.
|
|
|
|
Args:
|
|
int_color (int): A 32 bit value holding the binary RGBA value (where A
|
|
is ignored and forced to be fully opaque).
|
|
rgb (tuple): A tuple holding the integer values from 0-255 for (red, green, blue)
|
|
name (str): A name to assign to this color
|
|
'''
|
|
|
|
def __init__(self, int_color=None, rgb=None, name=None):
|
|
self.name = name
|
|
self._int_color = 0
|
|
if int_color is not None:
|
|
self._int_color = int_color | 0xff
|
|
elif rgb is not None:
|
|
self._int_color = (rgb[0] << 24) | (rgb[1] << 16) | (rgb[2] << 8) | 0xff
|
|
|
|
@property
|
|
def int_color(self):
|
|
'''int: The encoded integer value of the color.'''
|
|
return self._int_color
|
|
|
|
|
|
#: :class:`Color`: Green color instance.
|
|
green = Color(name="green", int_color=0x00ff00ff)
|
|
|
|
#: :class:`Color`: Red color instance.
|
|
red = Color(name="red", int_color=0xff0000ff)
|
|
|
|
#: :class:`Color`: Blue color instance.
|
|
blue = Color(name="blue", int_color=0x0000ffff)
|
|
|
|
#: :class:`Color`: White color instance.
|
|
white = Color(name="white", int_color=0xffffffff)
|
|
|
|
#: :class:`Color`: instance representing no color (LEDs off).
|
|
off = Color(name="off")
|
|
|
|
|
|
class Light:
|
|
'''Lights are used with LightCubes and Cozmo's backpack.
|
|
|
|
Lights may either be "on" or "off", though in practice any colors may be
|
|
assigned to either state (including no color/light).
|
|
'''
|
|
|
|
def __init__(self, on_color=off, off_color=off, on_period_ms=250,
|
|
off_period_ms=0, transition_on_period_ms=0, transition_off_period_ms=0):
|
|
self._on_color = on_color
|
|
self._off_color = off_color
|
|
self._on_period_ms = on_period_ms
|
|
self._off_period_ms = off_period_ms
|
|
self._transition_on_period_ms = transition_on_period_ms
|
|
self._transition_off_period_ms = transition_off_period_ms
|
|
|
|
@property
|
|
def on_color(self):
|
|
''':class:`Color`: The Color shown when the light is on.'''
|
|
return self._on_color
|
|
|
|
@on_color.setter
|
|
def on_color(self, color):
|
|
if not isinstance(color, Color):
|
|
raise TypeError("Must specify a Color")
|
|
self._on_color = color
|
|
|
|
@property
|
|
def off_color(self):
|
|
''':class:`Color`: The Color shown when the light is off.'''
|
|
return self._off_color
|
|
|
|
@off_color.setter
|
|
def off_color(self, color):
|
|
if not isinstance(color, Color):
|
|
raise TypeError("Must specify a Color")
|
|
self._off_color = color
|
|
|
|
@property
|
|
def on_period_ms(self):
|
|
'''int: The number of milliseconds the light should be "on" for for each cycle.'''
|
|
return self._on_period_ms
|
|
|
|
@on_period_ms.setter
|
|
def on_period_ms(self, ms):
|
|
if not 0 < ms < 2**32:
|
|
raise ValueError("Invalid value")
|
|
self._on_period_ms = ms
|
|
|
|
@property
|
|
def off_period_ms(self):
|
|
'''int: The number of milliseconds the light should be "off" for for each cycle.'''
|
|
return self._off_period_ms
|
|
|
|
@off_period_ms.setter
|
|
def off_period_ms(self, ms):
|
|
if not 0 < ms < 2**32:
|
|
raise ValueError("Invalid value")
|
|
self._off_period_ms = ms
|
|
|
|
@property
|
|
def transition_on_period_ms(self):
|
|
'''int: The number of milliseconds to take to transition the light to the on color.'''
|
|
return self._transition_on_period_ms
|
|
|
|
@transition_on_period_ms.setter
|
|
def transition_on_period_ms(self, ms):
|
|
if not 0 < ms < 2**32:
|
|
raise ValueError("Invalid value")
|
|
self._transition_on_period_ms = ms
|
|
|
|
@property
|
|
def transition_off_period_ms(self):
|
|
'''int: The number of milliseconds to take to transition the light to the off color.'''
|
|
return self._transition_off_period_ms
|
|
|
|
@transition_off_period_ms.setter
|
|
def transition_off_period_ms(self, ms):
|
|
if not 0 < ms < 2**32:
|
|
raise ValueError("Invalid value")
|
|
self._transition_off_period_ms = ms
|
|
|
|
def flash(self, on_period_ms=250, off_period_ms=250, off_color=off):
|
|
'''Convenience function to make a flashing version of an existing Light instance.
|
|
|
|
Args:
|
|
on_period_ms (int): The number of milliseconds the light should be "on" for for each cycle.
|
|
off_period_ms (int): The number of milliseconds the light should be "off" for for each cycle.
|
|
off_color (:class:`Color`): The color to flash to for the off state.
|
|
Returns:
|
|
:class:`Color` instance.
|
|
'''
|
|
flasher = copy.copy(self)
|
|
flasher.on_period_ms = on_period_ms
|
|
flasher.off_period_ms = off_period_ms
|
|
flasher.off_color=off_color
|
|
return flasher
|
|
|
|
def _set_light(msg, idx, light):
|
|
# For use with clad light messages specifically.
|
|
if not isinstance(light, Light):
|
|
raise TypeError("Expected a lights.Light")
|
|
msg.onColor[idx] = light.on_color.int_color
|
|
msg.offColor[idx] = light.off_color.int_color
|
|
msg.onPeriod_ms[idx] = light.on_period_ms
|
|
msg.offPeriod_ms[idx] = light.off_period_ms
|
|
msg.transitionOnPeriod_ms[idx] = light.transition_on_period_ms
|
|
msg.transitionOffPeriod_ms[idx] = light.transition_off_period_ms
|
|
|
|
#There is a glitch so it will always flash unless on_color==off_color
|
|
#ticket is COZMO-3319
|
|
|
|
#: :class:`Light`: A steady green colored LED light.
|
|
green_light = Light(on_color=green, off_color=green)
|
|
|
|
#: :class:`Light`: A steady red colored LED light.
|
|
red_light = Light(on_color=red, off_color=red)
|
|
|
|
#: :class:`Light`: A steady blue colored LED light.
|
|
blue_light = Light(on_color=blue, off_color=blue)
|
|
|
|
#: :class:`Light`: A steady white colored LED light.
|
|
white_light = Light(on_color=white, off_color=white)
|
|
|
|
#: :class:`Light`: A steady off (non-illuminated LED light).
|
|
off_light = Light(on_color=off, off_color=off)
|