Last active
February 19, 2023 09:08
-
-
Save tcpj/f0e4e7331c7836a21a0995d1ee082672 to your computer and use it in GitHub Desktop.
IKEA VINDSTYRKA MicroPython driver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from machine import Pin | |
# Constants | |
COMMAND_MODE = 0x80 | |
WRITE_MODE = 0xA0 | |
BIAS = 0x52 # Bias 1/2, 4 common | |
INT_OSC = 0x30 # Internal RC oscilator | |
SYS_DIS = 0x00 | |
SYS_EN = 0x02 | |
LCD_OFF = 0x04 | |
LCD_ON = 0x06 | |
WDT_DIS = 0x0A | |
class VK1621: | |
"""Basic VK1621 communication and stuff.""" | |
def __init__(self, *, CS_Pin, WR_Pin, DATA_Pin, BL_Pin): | |
self.CS = Pin(CS_Pin, Pin.OUT) | |
self.WR = Pin(WR_Pin, Pin.OUT) | |
self.DATA = Pin(DATA_Pin, Pin.OUT) | |
self.BL = Pin(BL_Pin, Pin.OUT) | |
self._ram = [False] * 128 | |
def clean_ram(self): | |
"""Clean the RAM content.""" | |
self._ram = [False] * 128 | |
def enable_display(self): | |
"""Initialize display.""" | |
self.command(BIAS) | |
self.command(INT_OSC) | |
self.command(SYS_DIS) | |
self.command(WDT_DIS) | |
self.command(SYS_EN) | |
self.command(LCD_ON) | |
self.BL.value(True) # Enable backlight. | |
def command(self, cmd): | |
"""Send commands in COMMAND mode.""" | |
self.CS.value(False) | |
self._write_bits(0x80, 4) # command mode | |
self._write_bits(cmd, 8) | |
self.CS.value(True) | |
def _write_bits(self, value, bits): | |
"""Write value's bits. Typically for sending bytes.""" | |
for _ in range(bits): | |
self.WR.value(False) # default state is high | |
self.DATA.value(value & 0x80 > 0) | |
value <<= 1 | |
self.WR.value(True) | |
def write_ram(self, ram): | |
"""Overwrite entire display RAM.""" | |
self.CS.value(False) # default state is high | |
self._write_bits(0xA0, 3) # enable write mode | |
self._write_bits(0x00, 6) # RAM address 0. | |
for bit in ram: | |
self.WR.value(False) | |
self.DATA.value(bit) | |
self.WR.value(True) | |
self.CS.value(True) # set chip select back to high | |
def edit_ram(self, address, value, size): | |
"""Modify ram content.""" | |
bit_mask = 0x1 << (size - 1) | |
for pos in range(size): | |
self._ram[address + pos] = value & bit_mask > 0 | |
value <<=1 | |
def show(self): | |
"""Show the content on display.""" | |
self.write_ram(self._ram) | |
class Vindstyrka(VK1621): | |
SEGMENT_MAP = { | |
"living_room_icon": 8, | |
"floor_indoor_icon": 16, | |
"window_icon": 24, | |
"pm2.5_icon": 101, | |
"pm2.5_number_1": 9, | |
"pm2.5_number_2": 17, | |
"pm2.5_number_3": 25, | |
"brightness_icon": 35, | |
"brightness_level": 32, | |
"thermometer_icon": 36, | |
"temperature_number_1": 37, | |
"temperature_number_2": 45, | |
"temperature_number_3": 53, | |
"auto_off_icon": 44, | |
"fahrenheit_icon": 52, | |
"fahrenheit_arrow": 61, | |
"celsius_icon": 63, | |
"celsius_arrow": 62, | |
"water_drop_icon": 64, | |
"humidity_number_1": 65, | |
"humidity_number_2": 73, | |
"humidity_number_3": 81, | |
"humidity_percent": 92, | |
"polen_icon": 72, | |
"polen_indicator": 93, | |
"polen_level_1": 95, | |
"polen_level_2": 94, | |
"polen_level_3": 88, | |
"tvoc_icon": 80, | |
"tvoc_arrow_up": 89, | |
"tvoc_arrow_down": 90, | |
"tvoc_arrow_right": 91, | |
"air_quality_green": 60, | |
"air_quality_green_yellow": 96, | |
"air_quality_yellow": 97, | |
"air_quality_yellow_red": 98, | |
"air_qiality_red": 99, | |
"ground_line": 100, | |
"air_cleaner_icon": 102, | |
"add_air_cleaner_icon": 107, | |
"pairing_icon": 103, | |
"house_icon": 104, | |
"trees_icon": 105, | |
"wrench_icon": 106, | |
} | |
NUMBERS = { | |
0: 95, | |
1: 6, | |
2: 61, | |
3: 47, | |
4: 102, | |
5: 107, | |
6: 123, | |
7: 14, | |
8: 127, | |
9: 111, | |
} | |
def toggle_icon(self, icon_name): | |
"""Toggle state of icon.""" | |
address = self.SEGMENT_MAP[icon_name] | |
new_state = not self._ram[address] | |
self.edit_ram(address=address, value=new_state, size=1) | |
self.show() | |
def set_pm25_value(self, value): | |
segments = ["pm2.5_number_1", "pm2.5_number_2", "pm2.5_number_3"] | |
self._set_numeric_segments(segments, value) | |
def set_temperature_value(self, value): | |
segments = ["temperature_number_1", "temperature_number_2", "temperature_number_3"] | |
self._set_numeric_segments(segments, value) | |
def set_humidity_value(self, value): | |
segments = ["humidity_number_1", "humidity_number_2", "humidity_number_3"] | |
self._set_numeric_segments(segments, value) | |
def _set_numeric_segments(self, segments, value, value_size): | |
numbers = [int(d) for d in str(value)] | |
active_digits = list(zip(numbers, segments)) | |
for digit, segment in active_digits: | |
digit_value = self.NUMBERS[digit] | |
segment_address = self.SEGMENT_MAP[segment] | |
self.edit_ram(segment_address, digit_value, 7) | |
self.show() | |
def show_ui(self): | |
for icon in [ | |
"house_icon", | |
"window_icon", | |
"house_icon", | |
"trees_icon", | |
"living_room_icon", | |
"floor_indoor_icon", | |
"ground_line", | |
"pm2.5_icon", | |
]: | |
self.toggle_icon(icon) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment