From 1e54d652e0d62751799162eccc1df15423fc07f8 Mon Sep 17 00:00:00 2001 From: androiddrew Date: Mon, 23 Dec 2019 19:46:56 -0500 Subject: [PATCH] Here are some updates --- .gitignore | 3 +- basics/boot.py | 2 +- kitchen_sink/README.md | 3 + kitchen_sink/main.py | 78 +++++++++++++++++++ kitchen_sink/ssd1306.py | 145 +++++++++++++++++++++++++++++++++++ light_sensor/README.md | 4 +- light_sensor/umqtt/simple.py | 12 +-- ssd1306_oled/README.md | 3 + ssd1306_oled/main.py | 11 ++- threading/README.md | 3 + threading/hello_threading.py | 11 +++ threading/threading2.py | 2 + 12 files changed, 266 insertions(+), 11 deletions(-) create mode 100644 kitchen_sink/README.md create mode 100644 kitchen_sink/main.py create mode 100644 kitchen_sink/ssd1306.py create mode 100644 threading/README.md create mode 100644 threading/hello_threading.py create mode 100644 threading/threading2.py diff --git a/.gitignore b/.gitignore index 11d7604..22ad12e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/ -/env \ No newline at end of file +/env +/binaries diff --git a/basics/boot.py b/basics/boot.py index 76821dd..514a936 100644 --- a/basics/boot.py +++ b/basics/boot.py @@ -15,7 +15,7 @@ def connect(): if not sta_if.isconnected(): print("connecting to wireless network....") sta_if.active(True) - sta_if.connect(b"Candy", b"whatisdelcious") + sta_if.connect(b"Candy", b"whatisdelicious") while not sta_if.isconnected(): pass print("network config:", sta_if.ifconfig()) diff --git a/kitchen_sink/README.md b/kitchen_sink/README.md new file mode 100644 index 0000000..66a2c08 --- /dev/null +++ b/kitchen_sink/README.md @@ -0,0 +1,3 @@ +# The Kitchen Sink + +This project uses most of the code from other projects. It pretty much does most things. diff --git a/kitchen_sink/main.py b/kitchen_sink/main.py new file mode 100644 index 0000000..fdb7837 --- /dev/null +++ b/kitchen_sink/main.py @@ -0,0 +1,78 @@ +from dht import DHT11 +from machine import Pin, SPI, ADC +from ssd1306 import SSD1306_SPI +from time import sleep + +# Buttons and Knobs Pins +BUTTON_PIN = Pin(34, Pin.IN) +POT_PIN = ADC(Pin(35)) + +# DHT Sensor +DHT_PIN = DHT11(Pin(26)) + +# SPI PINS +MISO_PIN = Pin(19) +MOSI_PIN = Pin(23) +SCK_PIN = Pin(18) +DC_PIN = Pin(4, Pin.OUT) +CS_PIN = Pin(5, Pin.OUT) +RST_PIN = Pin(2, Pin.OUT) + +# VSPI Hardware channel. 80 MHz signal rate +vspi = SPI(2, baudrate=2600000, polarity=0, phase=0, bits=8, firstbit=0, sck=SCK_PIN, mosi=MOSI_PIN, miso=MISO_PIN) + +oled = SSD1306_SPI(128, 64, vspi, DC_PIN, RST_PIN, CS_PIN) + + +class DisplayWriter: + + def __init__(self, spi): + self.spi = spi + self.height = spi.height + self.width = spi.width + + def msg(self, msg: str, l_offset=0, top_offset=0) -> None: + """Writes a message to an OLED display. + + Will wrap text as needed. + """ + self.spi.fill(0) + formatted_msg = self._split_msg(msg, l_offset, top_offset) + for s, left, top in formatted_msg: + self.spi.text(s, left, top) + self.spi.show() + + # Todo make this a generator + def _split_msg(self, msg, l_offset, top_offset) -> list: + """Splits a message at screen width to be used for text wrapping.""" + _top_offset = top_offset + result = [] + for e in msg.split('\n'): + result.append((e, l_offset, _top_offset)) + _top_offset += 10 + return result + + +def dht_report(dht_pin): + dht_pin.measure() + _temp = dht_pin.temperature() + _hum = dht_pin.humidity() + return _temp, _hum + + +def celsius_to_fahrenheit(celsius: int): + return (celsius * (9 / 5)) + 32 + + +display = DisplayWriter(oled) + +while True: + button_val = BUTTON_PIN.value() + light_sensor = round(POT_PIN.read() / 4096 * 100) + temp, hum = dht_report(DHT_PIN) + report = "Temp: {}C/{}F\nHum: {}%\nButton: {}\nLight: {}%".format(temp, celsius_to_fahrenheit(temp), hum, + button_val, light_sensor) + # print(report) + oled.invert(button_val) + display.msg(report) + sleep(0.1) diff --git a/kitchen_sink/ssd1306.py b/kitchen_sink/ssd1306.py new file mode 100644 index 0000000..78f06f0 --- /dev/null +++ b/kitchen_sink/ssd1306.py @@ -0,0 +1,145 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces +# https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py + +from micropython import const +import framebuf + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xa4) +SET_NORM_INV = const(0xa6) +SET_DISP = const(0xae) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xa0) +SET_MUX_RATIO = const(0xa8) +SET_COM_OUT_DIR = const(0xc0) +SET_DISP_OFFSET = const(0xd3) +SET_COM_PIN_CFG = const(0xda) +SET_DISP_CLK_DIV = const(0xd5) +SET_PRECHARGE = const(0xd9) +SET_VCOM_DESEL = const(0xdb) +SET_CHARGE_PUMP = const(0x8d) + + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP | 0x00, # off + # address setting + SET_MEM_ADDR, 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE | 0x00, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, 0x00, + SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, 0x80, + SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, + SET_VCOM_DESEL, 0x30, # 0.83*Vcc + # display + SET_CONTRAST, 0xff, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + # charge pump + SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP | 0x00) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b'\x40', None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) diff --git a/light_sensor/README.md b/light_sensor/README.md index 817d71c..ae3a5d2 100644 --- a/light_sensor/README.md +++ b/light_sensor/README.md @@ -1,3 +1,5 @@ # MQTT Light Sensor -This project uses a simple photo resistor to capture data and push the result to an MQTT broker. \ No newline at end of file +This project uses a simple photo resistor to capture data and push the result to an MQTT broker. + +It was one of my first attempts at build a Micropython project. \ No newline at end of file diff --git a/light_sensor/umqtt/simple.py b/light_sensor/umqtt/simple.py index 88f0d07..d1d7168 100644 --- a/light_sensor/umqtt/simple.py +++ b/light_sensor/umqtt/simple.py @@ -2,9 +2,11 @@ import usocket as socket import ustruct as struct from ubinascii import hexlify + class MQTTException(Exception): pass + class MQTTClient: def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0, @@ -85,7 +87,7 @@ class MQTTClient: self.sock.write(premsg, i + 2) self.sock.write(msg) - #print(hex(len(msg)), hexlify(msg, ":")) + # print(hex(len(msg)), hexlify(msg, ":")) self._send_str(self.client_id) if self.lw_topic: self._send_str(self.lw_topic) @@ -119,7 +121,7 @@ class MQTTClient: sz >>= 7 i += 1 pkt[i] = sz - #print(hex(len(pkt)), hexlify(pkt, ":")) + # print(hex(len(pkt)), hexlify(pkt, ":")) self.sock.write(pkt, i + 1) self._send_str(topic) if qos > 0: @@ -146,7 +148,7 @@ class MQTTClient: pkt = bytearray(b"\x82\0\0\0") self.pid += 1 struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) - #print(hex(len(pkt)), hexlify(pkt, ":")) + # print(hex(len(pkt)), hexlify(pkt, ":")) self.sock.write(pkt) self._send_str(topic) self.sock.write(qos.to_bytes(1, "little")) @@ -154,7 +156,7 @@ class MQTTClient: op = self.wait_msg() if op == 0x90: resp = self.sock.read(4) - #print(resp) + # print(resp) assert resp[1] == pkt[2] and resp[2] == pkt[3] if resp[3] == 0x80: raise MQTTException(resp[3]) @@ -201,4 +203,4 @@ class MQTTClient: # the same processing as wait_msg. def check_msg(self): self.sock.setblocking(False) - return self.wait_msg() \ No newline at end of file + return self.wait_msg() diff --git a/ssd1306_oled/README.md b/ssd1306_oled/README.md index 5ea9e00..0e9040c 100644 --- a/ssd1306_oled/README.md +++ b/ssd1306_oled/README.md @@ -30,4 +30,7 @@ To invert colors: oled.invert(True) ``` +A `DisplayWriter` was added as a convenience to writing out messages to the OLED. Use this for printing text messages to the display. Newline characters will dwa +``` +``` diff --git a/ssd1306_oled/main.py b/ssd1306_oled/main.py index 4386cca..a45b174 100644 --- a/ssd1306_oled/main.py +++ b/ssd1306_oled/main.py @@ -6,7 +6,7 @@ from time import sleep # DHT Sensor DHT_PIN = DHT11(Pin(26)) -# OLD PINS +# SPI PINS MISO_PIN = Pin(19) MOSI_PIN = Pin(23) SCK_PIN = Pin(18) @@ -56,11 +56,16 @@ def dht_report(dht_pin): return _temp, _hum +def celsius_to_fahrenheit(celsius: int): + return (celsius * (9 / 5)) + 32 + + display = DisplayWriter(oled) while True: - temp, hum = dht_report(DHT_PIN) - report = "Temp: {}C\nHum: {}%".format(temp, hum) + cel, hum = dht_report(DHT_PIN) + fahr = celsius_to_fahrenheit(cel) + report = "Temp: {}C/{}F\nHum: {}%".format(cel, fahr, hum) print(report) display.msg(report) sleep(1) diff --git a/threading/README.md b/threading/README.md new file mode 100644 index 0000000..652d4e4 --- /dev/null +++ b/threading/README.md @@ -0,0 +1,3 @@ +# Threading + +The ESP32 has two cores, but Micropython will only run in single core mode. We can however use threading. diff --git a/threading/hello_threading.py b/threading/hello_threading.py new file mode 100644 index 0000000..255bd3f --- /dev/null +++ b/threading/hello_threading.py @@ -0,0 +1,11 @@ +import _thread +import time + + +def testThread(): + while True: + print("Hello threading") + time.sleep(15) # Time is so high so that we can actually get a repl. + + +_thread.start_new_thread(testThread, ()) diff --git a/threading/threading2.py b/threading/threading2.py new file mode 100644 index 0000000..9569956 --- /dev/null +++ b/threading/threading2.py @@ -0,0 +1,2 @@ +import _thread +