Skip to content

Instantly share code, notes, and snippets.

@tcpj
Last active February 19, 2023 09:08
Show Gist options
  • Save tcpj/f0e4e7331c7836a21a0995d1ee082672 to your computer and use it in GitHub Desktop.
Save tcpj/f0e4e7331c7836a21a0995d1ee082672 to your computer and use it in GitHub Desktop.
IKEA VINDSTYRKA MicroPython driver
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