1"""
2Module for controlling the LED matrix or reading environment data on the SenseHat of a Raspberry Pi.
3
4.. versionadded:: 2017.7.0
5
6:maintainer:    Benedikt Werner <1benediktwerner@gmail.com>, Joachim Werner <joe@suse.com>
7:maturity:      new
8:depends:       sense_hat Python module
9
10The rotation of the Pi can be specified in a pillar.
11This is useful if the Pi is used upside down or sideways to correct the orientation of the image being shown.
12
13Example:
14
15.. code-block:: yaml
16
17    sensehat:
18        rotation: 90
19
20"""
21
22
23import logging
24
25try:
26    from sense_hat import SenseHat
27
28    has_sense_hat = True
29except (ImportError, NameError):
30    _sensehat = None
31    has_sense_hat = False
32
33log = logging.getLogger(__name__)
34
35
36def __virtual__():
37    """
38    Only load the module if SenseHat is available
39    """
40    if has_sense_hat:
41        try:
42            _sensehat = SenseHat()
43        except OSError:
44            return (
45                False,
46                "This module can only be used on a Raspberry Pi with a SenseHat.",
47            )
48
49        rotation = __salt__["pillar.get"]("sensehat:rotation", 0)
50        if rotation in [0, 90, 180, 270]:
51            _sensehat.set_rotation(rotation, False)
52        else:
53            log.error("%s is not a valid rotation. Using default rotation.", rotation)
54        return True
55
56    return (
57        False,
58        "The SenseHat execution module cannot be loaded: 'sense_hat' python library"
59        " unavailable.",
60    )
61
62
63def set_pixels(pixels):
64    """
65    Sets the entire LED matrix based on a list of 64 pixel values
66
67    pixels
68        A list of 64 ``[R, G, B]`` color values.
69    """
70    _sensehat.set_pixels(pixels)
71    return {"pixels": pixels}
72
73
74def get_pixels():
75    """
76    Returns a list of 64 smaller lists of ``[R, G, B]`` pixels representing the
77    the currently displayed image on the LED matrix.
78
79    .. note::
80        When using ``set_pixels`` the pixel values can sometimes change when
81        you read them again using ``get_pixels``. This is because we specify each
82        pixel element as 8 bit numbers (0 to 255) but when they're passed into the
83        Linux frame buffer for the LED matrix the numbers are bit shifted down
84        to fit into RGB 565. 5 bits for red, 6 bits for green and 5 bits for blue.
85        The loss of binary precision when performing this conversion
86        (3 bits lost for red, 2 for green and 3 for blue) accounts for the
87        discrepancies you see.
88
89        The ``get_pixels`` method provides an accurate representation of how the
90        pixels end up in frame buffer memory after you have called ``set_pixels``.
91    """
92    return _sensehat.get_pixels()
93
94
95def set_pixel(x, y, color):
96    """
97    Sets a single pixel on the LED matrix to a specified color.
98
99    x
100        The x coordinate of the pixel. Ranges from 0 on the left to 7 on the right.
101    y
102        The y coordinate of the pixel. Ranges from 0 at the top to 7 at the bottom.
103    color
104        The new color of the pixel as a list of ``[R, G, B]`` values.
105
106    CLI Example:
107
108    .. code-block:: bash
109
110        salt 'raspberry' sensehat.set_pixel 0 0 '[255, 0, 0]'
111    """
112    _sensehat.set_pixel(x, y, color)
113    return {"color": color}
114
115
116def get_pixel(x, y):
117    """
118    Returns the color of a single pixel on the LED matrix.
119
120    x
121        The x coordinate of the pixel. Ranges from 0 on the left to 7 on the right.
122    y
123        The y coordinate of the pixel. Ranges from 0 at the top to 7 at the bottom.
124
125    .. note::
126        Please read the note for ``get_pixels``
127    """
128    return _sensehat.get_pixel(x, y)
129
130
131def low_light(low_light=True):
132    """
133    Sets the LED matrix to low light mode. Useful in a dark environment.
134
135    CLI Example:
136
137    .. code-block:: bash
138
139        salt 'raspberry' sensehat.low_light
140        salt 'raspberry' sensehat.low_light False
141    """
142    _sensehat.low_light = low_light
143    return {"low_light": low_light}
144
145
146def show_message(
147    message, msg_type=None, text_color=None, back_color=None, scroll_speed=0.1
148):
149    """
150    Displays a message on the LED matrix.
151
152    message
153        The message to display
154    msg_type
155        The type of the message. Changes the appearance of the message.
156
157        Available types are::
158
159            error:      red text
160            warning:    orange text
161            success:    green text
162            info:       blue text
163
164    scroll_speed
165        The speed at which the message moves over the LED matrix.
166        This value represents the time paused for between shifting the text
167        to the left by one column of pixels. Defaults to '0.1'.
168    text_color
169        The color in which the message is shown. Defaults to '[255, 255, 255]' (white).
170    back_color
171        The background color of the display. Defaults to '[0, 0, 0]' (black).
172
173    CLI Example:
174
175    .. code-block:: bash
176
177        salt 'raspberry' sensehat.show_message 'Status ok'
178        salt 'raspberry' sensehat.show_message 'Something went wrong' error
179        salt 'raspberry' sensehat.show_message 'Red' text_color='[255, 0, 0]'
180        salt 'raspberry' sensehat.show_message 'Hello world' None '[0, 0, 255]' '[255, 255, 0]' 0.2
181    """
182    text_color = text_color or [255, 255, 255]
183    back_color = back_color or [0, 0, 0]
184
185    color_by_type = {
186        "error": [255, 0, 0],
187        "warning": [255, 100, 0],
188        "success": [0, 255, 0],
189        "info": [0, 0, 255],
190    }
191
192    if msg_type in color_by_type:
193        text_color = color_by_type[msg_type]
194
195    _sensehat.show_message(message, scroll_speed, text_color, back_color)
196    return {"message": message}
197
198
199def show_letter(letter, text_color=None, back_color=None):
200    """
201    Displays a single letter on the LED matrix.
202
203    letter
204        The letter to display
205    text_color
206        The color in which the letter is shown. Defaults to '[255, 255, 255]' (white).
207    back_color
208        The background color of the display. Defaults to '[0, 0, 0]' (black).
209
210    CLI Example:
211
212    .. code-block:: bash
213
214        salt 'raspberry' sensehat.show_letter O
215        salt 'raspberry' sensehat.show_letter X '[255, 0, 0]'
216        salt 'raspberry' sensehat.show_letter B '[0, 0, 255]' '[255, 255, 0]'
217    """
218    text_color = text_color or [255, 255, 255]
219    back_color = back_color or [0, 0, 0]
220
221    _sensehat.show_letter(letter, text_color, back_color)
222    return {"letter": letter}
223
224
225def show_image(image):
226    """
227    Displays an 8 x 8 image on the LED matrix.
228
229    image
230        The path to the image to display. The image must be 8 x 8 pixels in size.
231
232    CLI Example:
233
234    .. code-block:: bash
235
236        salt 'raspberry' sensehat.show_image /tmp/my_image.png
237    """
238    return _sensehat.load_image(image)
239
240
241def clear(color=None):
242    """
243    Sets the LED matrix to a single color or turns all LEDs off.
244
245    CLI Example:
246
247    .. code-block:: bash
248
249        salt 'raspberry' sensehat.clear
250        salt 'raspberry' sensehat.clear '[255, 0, 0]'
251    """
252    if color is None:
253        _sensehat.clear()
254    else:
255        _sensehat.clear(color)
256    return {"color": color}
257
258
259def get_humidity():
260    """
261    Get the percentage of relative humidity from the humidity sensor.
262    """
263    return _sensehat.get_humidity()
264
265
266def get_pressure():
267    """
268    Gets the current pressure in Millibars from the pressure sensor.
269    """
270    return _sensehat.get_pressure()
271
272
273def get_temperature():
274    """
275    Gets the temperature in degrees Celsius from the humidity sensor.
276    Equivalent to calling ``get_temperature_from_humidity``.
277
278    If you get strange results try using ``get_temperature_from_pressure``.
279    """
280    return _sensehat.get_temperature()
281
282
283def get_temperature_from_humidity():
284    """
285    Gets the temperature in degrees Celsius from the humidity sensor.
286    """
287    return _sensehat.get_temperature_from_humidity()
288
289
290def get_temperature_from_pressure():
291    """
292    Gets the temperature in degrees Celsius from the pressure sensor.
293    """
294    return _sensehat.get_temperature_from_pressure()
295