From f3b6cd1d7391d60498ebd5a84e000591ae37aa29 Mon Sep 17 00:00:00 2001 From: Dmytro Shestakov Date: Wed, 2 Nov 2022 18:38:53 +0200 Subject: [PATCH] Add TM1637 driver written in Berry It allows to use this type of display in addition to any standard Tasmota display simultaneously --- tasmota/berry/drivers/tm1637.be | 190 ++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 tasmota/berry/drivers/tm1637.be diff --git a/tasmota/berry/drivers/tm1637.be b/tasmota/berry/drivers/tm1637.be new file mode 100644 index 000000000..9e7b572f0 --- /dev/null +++ b/tasmota/berry/drivers/tm1637.be @@ -0,0 +1,190 @@ +#- +Simplified Tasmota TM1637 driver written in Berry +Might be helpful in the case of using multiple displays +Supports only the 4 digit basic display + +DIO_PIN and CLK_PIN are your esp32 pin numbers +How to use + +> load('tm1637') +> tm = Tm1637(DIO_PIN, CLK_PIN) +> tm.set_on(4) +> tm.print('0123') +> tm.print(456) + +Add custom commands to the native Tasmota console: +> tm_add_custom_commands(DIO_PIN, CLK_PIN) + +And then: +TmBrightness 2 +TmPrint 0123 +TmPrint -5.67 + +Note: adding these commands to autoexec.be should be performed via creating an additional .be file with the content: + tm_add_custom_commands(DIO_PIN, CLK_PIN) + +and then loading it in autoexec.be via load('tm1637') and load('script_name') +The direct addition may not work +-# + +class Tm1637 + static var CMD_CTRL = 0x80 + static var CMD_DISP_ON = 0x08 + static var CMD_DATA = 0x40 + static var CMD_ADDR = 0xC0 + + static var SYMB_DOT = 0x80 + + static var DIGIT_MAP = { + '0': 0x3F, + '1': 0x06, + '2': 0x5B, + '3': 0x4F, + '4': 0x66, + '5': 0x6D, + '6': 0x7D, + '7': 0x07, + '8': 0x7F, + '9': 0x6F, + '-': 0x40, + ' ': 0x00 + } + + var PIN_DIO + var PIN_CLK + + def init(dio, clk) + self.PIN_DIO = dio + self.PIN_CLK = clk + gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT) + gpio.pin_mode(self.PIN_CLK, gpio.OUTPUT) + gpio.digital_write(self.PIN_DIO, 1) + gpio.digital_write(self.PIN_CLK, 1) + end + + def start() + gpio.digital_write(self.PIN_DIO, 1) + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_DIO, 0) + end + + def stop() + gpio.digital_write(self.PIN_CLK, 0) + gpio.digital_write(self.PIN_DIO, 0) + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_DIO, 1) + end + + def ack() + gpio.digital_write(self.PIN_CLK, 0) + gpio.pin_mode(self.PIN_DIO, gpio.INPUT_PULLUP) + var ack_state = gpio.digital_read(self.PIN_DIO) == 0 + gpio.digital_write(self.PIN_CLK, 1) + gpio.digital_write(self.PIN_CLK, 0) + gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT) + return ack_state + end + + def write_bit(bitval) + gpio.digital_write(self.PIN_CLK, 0) + gpio.digital_write(self.PIN_DIO, bitval) + gpio.digital_write(self.PIN_CLK, 1) + end + + def write_byte(byteval) + for pos: 0..7 + self.write_bit((byteval >> pos) & 0x01) + end + end + + def send_command(command) + self.start() + self.write_byte(command) + var ack_state = self.ack() + self.stop() + return ack_state + end + + def send_data(data) + var ack_state = true + self.start() + for i : 0..size(data)-1 + self.write_byte(data[i]) + ack_state = self.ack() && ack_state + end + self.stop() + return ack_state + end + + # 0-8 range, 0 to 'OFF' + def set_on(brightness) + if brightness == nil || brightness > 8 + brightness = 8 + elif brightness < 0 + brightness = 0 + end + var cmd = self.CMD_CTRL + if brightness + cmd |= self.CMD_DISP_ON + brightness -= 1 + end + return self.send_command(cmd | brightness) + end + + def print(num) + import string + + num = str(num) + var max_str_len = 4 + + do + var dot_pos = string.find(num, '.') + if dot_pos >= 0 && dot_pos < 5 + max_str_len = 5 + end + end + if size(num) > max_str_len + num = string.split(num, max_str_len)[0] + end + num = string.format('%4s', num) + var payload = bytes(-5) + payload[0] = self.CMD_ADDR + var int_offset = 1 + for i : 0..size(num)-1 + if num[i] == '.' + payload[i] |= self.SYMB_DOT + int_offset = 0 + else + payload[i + int_offset] = self.DIGIT_MAP[num[i]] + end + end + var ack_state = self.send_command(self.CMD_DATA) && self.send_data(payload) + if !ack_state + log('TM1637 - no ACK, please check connections') + end + return ack_state + end + + def clear() + self.print(' ') + end + + # Won't be called on the system restart + def deinit() + self.set_on(0) + end +end + +def tm_add_custom_commands(dio, clk) + var tm = Tm1637(dio, clk) + tm.clear() + tm.set_on(4) + tasmota.add_cmd('tmprint', def(cmd, idx, payload) + tm.print(payload) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed() + end) + # 0-8 range, 0 to 'OFF' + tasmota.add_cmd('tmbrightness', def(cmd, idx, payload) + tm.set_on(int(payload)) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed() + end) + log("Tasmota custom commands registered: TmPrint, TmBrightness") +end