108 |
134 |
135 |
136 | """
137 |
138 | addr = socket.getaddrinfo("192.168.4.1", 80)[0][-1]
139 | s = socket.socket()
140 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
141 | s.bind(addr)
142 | s.listen(5)
143 | connection_count = 0
144 |
145 | while True:
146 | cl, addr = s.accept()
147 | print(connection_count, "connection on", addr)
148 | print("Free in: %d" % gc.mem_free())
149 | connection_count += 1
150 | cl_file = cl.makefile("rwb", 0)
151 | while True:
152 | h = cl_file.readline()
153 | gotten_msg = b"GET /?messageinput="
154 | if gotten_msg in h:
155 | msg = h.decode("utf-8").split("/?messageinput=")
156 | final_msg = msg[1][:(len(msg)-12)]
157 | write_file(final_msg)
158 | elif b"GET /?cl=yes" in h:
159 | clear_file()
160 | if h == b"" or h == b"\r\n":
161 | break
162 | rows = linted_data()
163 | response = html % "\n".join(rows)
164 | try:
165 | cl.sendall(response)
166 | except OSError as error:
167 | print("Error trying to send all information. %s" % error)
168 | pass
169 | cl.close()
170 | print("Free out: %d" % gc.mem_free())
171 |
172 | main()
173 |
--------------------------------------------------------------------------------
/projects/camera_slider/README.md:
--------------------------------------------------------------------------------
1 | # Camera slider.
--------------------------------------------------------------------------------
/projects/camera_slider/code/camera_slider.py:
--------------------------------------------------------------------------------
1 | """This project uses the module uln2003 that you can find
2 | at https://github.com/yeyeto2788/MicroPythonScripts/blob/master/modules/uln2003/release/uln2003.py
3 | """
4 | import time
5 | from machine import Pin
6 | from uln2003 import Stepper, FULL_ROTATION, HALF_STEP
7 |
8 | start_switch = Pin(4, Pin.IN, Pin.PULL_UP)
9 | end_switch = Pin(5, Pin.IN, Pin.PULL_UP)
10 |
11 | SLOW = 5500
12 | FAST = 4000
13 | FORWARD = 1
14 | BACKWARD = -1
15 | motor = Stepper(HALF_STEP, 15, 13, 12, 14, delay=FAST)
16 |
17 |
18 | def fast_move(fn):
19 | original = motor.delay
20 |
21 | def wrapper(*args, **kwargs):
22 | motor.delay = FAST
23 | value = fn(*args, **kwargs)
24 | return value
25 |
26 | motor.delay = original
27 | return wrapper
28 |
29 |
30 | def slow_move(fn):
31 | original = motor.delay
32 |
33 | def wrapper(*args, **kwargs):
34 | motor.delay = SLOW
35 | value = fn(*args, **kwargs)
36 | return value
37 |
38 | motor.delay = original
39 | return wrapper
40 |
41 |
42 | @fast_move
43 | def home_motor():
44 | """Home the motor to its starting position.
45 |
46 | The motor will start spindle until the end switch is activated.
47 | """
48 | while start_switch.value():
49 | motor.step(1, BACKWARD)
50 |
51 | motor.step(10)
52 | motor.current_position = 0
53 |
54 |
55 | @fast_move
56 | def get_slider_size():
57 | """Get the number of steps to get to the end of the slider.
58 |
59 | It will first home the motor and start recording the steps to get
60 | to the end of the slider and then home the motor again.
61 | """
62 | home_motor()
63 |
64 | while end_switch.value():
65 | motor.step(1)
66 |
67 | slider_length = motor.current_position
68 | home_motor()
69 | return slider_length
70 |
71 |
72 | def timed_steps(steps, secs, count, callback=None):
73 | """Move the motor given steps, wait given seconds for an n given times.
74 |
75 | Args:
76 | steps: Steps to be done by the motor.
77 | secs: Seconds to wait until next turn.
78 | count: Number of time to do the repetition.
79 | callback: Function to be executed on each iteration.
80 | """
81 |
82 | for iteration in range(count):
83 | motor.step(steps)
84 |
85 | if callback is not None:
86 | callback()
87 |
88 | if iteration == (count - 1):
89 | break
90 |
91 | time.sleep(secs)
92 |
93 |
94 | def go_to(destination):
95 | """Move the motor to a desired step number.
96 |
97 | The movement will be perform based on the current position of
98 | the motor.
99 | """
100 | current_pos = motor.current_position
101 |
102 | if current_pos > destination:
103 | movement = current_pos - destination
104 | direction = BACKWARD
105 | else:
106 | movement = destination - current_pos
107 | direction = FORWARD
108 | motor.step(movement, direction)
109 |
110 |
111 | def move_to(start, end):
112 | """Perform a movement from point A to point B.
113 |
114 | First go to point A and then perform the movement to point
115 | B.
116 | """
117 | go_to(start)
118 |
119 | if start < end:
120 | direction = FORWARD
121 | x1 = start
122 | x2 = end
123 | else:
124 | direction = BACKWARD
125 | x1 = end
126 | x2 = start
127 | motor.step(x2 - x1, direction)
128 |
--------------------------------------------------------------------------------
/projects/camera_slider/release/camera_slider.py:
--------------------------------------------------------------------------------
1 | import time
2 | from machine import Pin
3 | from uln2003 import Stepper,FULL_ROTATION,HALF_STEP
4 | start_switch=Pin(4,Pin.IN,Pin.PULL_UP)
5 | end_switch=Pin(5,Pin.IN,Pin.PULL_UP)
6 | SLOW=5500
7 | FAST=4000
8 | FORWARD=1
9 | BACKWARD=-1
10 | motor=Stepper(HALF_STEP,15,13,12,14,delay=FAST)
11 | def fast_move(fn):
12 | original=motor.delay
13 | def wrapper(*args,**kwargs):
14 | motor.delay=FAST
15 | value=fn(*args,**kwargs)
16 | return value
17 | motor.delay=original
18 | return wrapper
19 | def slow_move(fn):
20 | original=motor.delay
21 | def wrapper(*args,**kwargs):
22 | motor.delay=SLOW
23 | value=fn(*args,**kwargs)
24 | return value
25 | motor.delay=original
26 | return wrapper
27 | @fast_move
28 | def home_motor():
29 | while start_switch.value():
30 | motor.step(1,BACKWARD)
31 | motor.step(10)
32 | motor.current_position=0
33 | @fast_move
34 | def get_slider_size():
35 | home_motor()
36 | while end_switch.value():
37 | motor.step(1)
38 | slider_length=motor.current_position
39 | home_motor()
40 | return slider_length
41 | def timed_steps(steps,secs,count,callback=None):
42 | for iteration in range(count):
43 | motor.step(steps)
44 | if callback is not None:
45 | callback()
46 | if iteration==(count-1):
47 | break
48 | time.sleep(secs)
49 | def go_to(destination):
50 | current_pos=motor.current_position
51 | if current_pos>destination:
52 | movement=current_pos-destination
53 | direction=BACKWARD
54 | else:
55 | movement=destination-current_pos
56 | direction=FORWARD
57 | motor.step(movement,direction)
58 | def move_to(start,end):
59 | go_to(start)
60 | if start
2 |
3 |
4 |
5 |
6 | Reading the file!
7 |
34 |
35 |
36 |
37 |
Hello from micropython
38 |
39 |
40 |
41 |
42 |
Sensor
43 |
Value
44 |
Timestamp
45 |
46 |
47 |
Temperature
48 |
10
49 |
10:00
50 |
51 |
52 |
Temperature
53 |
11
54 |
11:00
55 |
56 |
57 |
Luminosity
58 |
11
59 |
11:00
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/projects/micro_server/code/micro_server.py:
--------------------------------------------------------------------------------
1 | import picoweb
2 | import network
3 |
4 | app = picoweb.WebApp("app")
5 |
6 | @app.route("/")
7 | def index(req, resp):
8 | yield from picoweb.start_response(resp, content_type="text/html")
9 |
10 | html_file = open('index.html', 'r')
11 |
12 | for line in html_file:
13 | yield from resp.awrite(line)
14 |
15 | def get_ip():
16 | wlan = network.WLAN(network.STA_IF)
17 | if wlan.active():
18 | addr = wlan.ifconfig()[0]
19 | else:
20 | wlan = network.WLAN(network.AP_IF)
21 | if wlan.active():
22 | addr = wlan.ifconfig()[0]
23 | else:
24 | print("No active connection")
25 | return addr
26 |
27 | host_ip = get_ip()
28 | app.run(debug=True, host=host_ip)
29 |
--------------------------------------------------------------------------------
/projects/micro_server/release/micro_server.py:
--------------------------------------------------------------------------------
1 | # This file is executed on every boot (including wake-boot from deepsleep)
2 |
3 | import gc
4 | import os
5 |
6 | def do_connect():
7 | import network
8 | sta_if = network.WLAN(network.STA_IF)
9 | ap_if = network.WLAN(network.AP_IF)
10 | if not sta_if.isconnected():
11 | print('connecting to network...')
12 | sta_if.active(True)
13 | sta_if.connect('', '')
14 | while not sta_if.isconnected():
15 | pass
16 | print('network config:', sta_if.ifconfig())
17 |
18 | do_connect()
19 | gc.collect()
20 |
--------------------------------------------------------------------------------
/projects/pomodoro/README.md:
--------------------------------------------------------------------------------
1 | # MicroPomodoro
2 |
3 | This is a script that is used to implement the Pomodoro Technique, with a 25 mins working time and 5 mins break.
4 |
5 | This uses the OLED LCD display on the board to show the remaining time, once the time finishes the alarm will go off.
6 |
7 | What we need to do is download all the code from the **`Release`** folder and rename the **`pomodoro.py`** file to **`main.py`** so it will be executed after booting up.
8 |
9 | ## Parts needed:
10 |
11 | - ESP8266
12 |
13 | I'm using the Wemos D1 Mini board.
14 |
15 |
32 |
33 | ## Custom PCB for the project.
34 |
35 |
36 |
37 |
38 |
Version
39 |
Top side of the board
40 |
Placement of components
41 |
Comments
42 |
43 |
44 |
Version 0.1
45 |
46 |
47 |
Use this version if you do not wish to use the OLED LCD display.
48 |
49 |
50 |
Version 0.2
51 |
52 |
53 |
This version comes with 4 push buttons and 2 I2C connectors. You can see schematics here.
54 |
55 |
56 |
57 |
58 | The idea with this board it not to have wires all over and also makes it better for fitting it into a 3D printed case (If anyone can help me out would be great) and also for connecting it to the Wemos D1 mini board.
59 |
60 | ~~I'll try to keep the design for single side PCB.~~ Since the price of making the PCBs is not that expensive, I decided to make it double sided to add more things on the board.
61 |
62 | Eagle CAD files are within the **`Release`** folder
63 |
64 | #### Bill of materials
65 |
66 |
67 |
68 |
Item
69 |
Quantity
70 |
71 |
72 |
WS2812B Neopixel
73 |
12
74 |
75 |
76 |
100 pf Capacitor (SMD 1206)
77 |
12
78 |
79 |
80 |
SMD 1k Resistor (SMD 1206)
81 |
4
82 |
83 |
84 |
6mm Push button
85 |
4
86 |
87 |
88 |
Plain PCB (around 6x6 cm)
89 |
1
90 |
91 |
92 |
93 | **The PCB is still in testing stage.** (Currently testing Version 0.2)
94 |
95 | ## Useful links:
96 |
97 | [Pomodoro Technique](https://en.wikipedia.org/wiki/Pomodoro_Technique)
98 |
99 | ## TO DO:
100 |
101 | - [ ] Add real execution image.
102 |
103 | - [ ] Better documentation.
104 |
105 | - [ ] Add buzzer ring alarm when finish.
106 |
107 | - [ ] Add Eagle CAD design file, Gerber files and PDF for manual PCB manufacturing.
108 |
- [x] Eagle Files
109 |
- [ ] Gerber files.
110 |
- [X] PDF files.
111 |
112 | - [x] Add led or neopixel (Optional).
113 |
114 | - [x] Add button execution.
115 |
--------------------------------------------------------------------------------
/projects/pomodoro/code/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "screen":{
3 | "width":128,
4 | "height":64,
5 | "sda":4,
6 | "scl":5
7 | },
8 | "neopixel":{
9 | "count":12,
10 | "pin":12,
11 | "brightness": 20
12 | },
13 | "button_ul": {
14 | "pin": 14
15 | },
16 | "button_ur": {
17 | "pin": 0
18 | },
19 | "button_dl": {
20 | "pin": 13
21 | },
22 | "button_dr": {
23 | "pin": 2
24 | },
25 | "colors":{
26 | "red":[255, 0, 0],
27 | "green":[0, 255, 0],
28 | "blue":[0, 0, 255],
29 | "yellow":[0, 255, 255],
30 | "white":[255, 255, 255],
31 | "nocolor":[0, 0, 0]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/projects/pomodoro/docs/images/v01_pomodoro_pcb_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/docs/images/v01_pomodoro_pcb_top.png
--------------------------------------------------------------------------------
/projects/pomodoro/docs/images/v01_pomodoro_pcb_top_placement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/docs/images/v01_pomodoro_pcb_top_placement.png
--------------------------------------------------------------------------------
/projects/pomodoro/docs/images/v02_pomodoro_pcb_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/docs/images/v02_pomodoro_pcb_bottom.png
--------------------------------------------------------------------------------
/projects/pomodoro/docs/images/v02_pomodoro_pcb_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/docs/images/v02_pomodoro_pcb_top.png
--------------------------------------------------------------------------------
/projects/pomodoro/docs/pdf/schematics_v02.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/docs/pdf/schematics_v02.pdf
--------------------------------------------------------------------------------
/projects/pomodoro/hardware/02/3D_Case/STL/uPomodoro Case.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/hardware/02/3D_Case/STL/uPomodoro Case.stl
--------------------------------------------------------------------------------
/projects/pomodoro/hardware/02/3D_Case/uPomodoro Case.f3z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/hardware/02/3D_Case/uPomodoro Case.f3z
--------------------------------------------------------------------------------
/projects/pomodoro/release/PCB/v0.1/MicroPomodoro_schematics.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/pomodoro/release/PCB/v0.1/MicroPomodoro_schematics.pdf
--------------------------------------------------------------------------------
/projects/pomodoro/release/boot.py:
--------------------------------------------------------------------------------
1 | # This file is executed on every boot (including wake-boot from deepsleep)
2 | import gc
3 | gc.collect()
4 |
5 | import pomodoro
6 | pomodoro.main_logic()
7 |
--------------------------------------------------------------------------------
/projects/pomodoro/release/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "screen":{
3 | "width":128,
4 | "height":64,
5 | "sda":4,
6 | "scl":5
7 | },
8 | "neopixel":{
9 | "count":12,
10 | "pin":12,
11 | "brightness": 20
12 | },
13 | "button_ul": {
14 | "pin": 14
15 | },
16 | "button_ur": {
17 | "pin": 0
18 | },
19 | "button_dl": {
20 | "pin": 13
21 | },
22 | "button_dr": {
23 | "pin": 2
24 | },
25 | "colors":{
26 | "red":[255, 0, 0],
27 | "green":[0, 255, 0],
28 | "blue":[0, 0, 255],
29 | "yellow":[0, 255, 255],
30 | "white":[255, 255, 255],
31 | "nocolor":[0, 0, 0]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/projects/pomodoro/release/pomodoro.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | import machine
4 | import neopixel
5 | import urandom
6 | try:
7 | import ssd1306
8 | blndisplay=True
9 | except ImportError as error:
10 | print("Seems like there is no such module",error)
11 | blndisplay=False
12 | def load_config():
13 | with open("config.json", "r")as conf_file:
14 | return json.load(conf_file)
15 | config=load_config()
16 | def slow_fill_color(neostrip,colors,pstrColor,pixel_count):
17 | for i in range(0,pixel_count):
18 | neostrip[i]=colors[pstrColor]
19 | time.sleep_ms(25)
20 | neostrip.write()
21 | def get_random_int():
22 | int_return=urandom.getrandbits(8)
23 | if int_return<256:
24 | return int_return
25 | else:
26 | return 0
27 | def display_msg(message,line,start=0,show=0):
28 | lines=[0,8,16,24,32,40,48]
29 | if line in lines:
30 | display.text(message,start,line)
31 | if show:
32 | display.show()
33 | def clear_display(fill=0,show=0):
34 | display.fill(fill)
35 | if show:
36 | display.show()
37 | def print_text(text):
38 | clear_display()
39 | fill_amount=16
40 | display_msg("*"*fill_amount,24,0,1)
41 | display_msg('{:*^16}'.format(text),32,0,1)
42 | display_msg("*"*fill_amount,40,0,1)
43 | time.sleep(1)
44 | clear_display(0,1)
45 | def lapse_time(neostrip,minutes,color,message=''):
46 | t_mins=minutes-1
47 | for mins in range(t_mins,-1,-1):
48 | for secs in range(60,0,-1):
49 | data='{:02d} : {:02d}'.format(mins,secs)
50 | print("Remaining time:",data)
51 | for milisecs in range(40,0,-1):
52 | set_pixel_color(neostrip,milisecs%12,color)
53 | time.sleep_ms(25)
54 | if blndisplay:
55 | clear_display()
56 | display_msg(data,24,32)
57 | display_msg('{:^16}'.format(message),0)
58 | display.show()
59 | def set_pixel_color(neostrip,neopixel,color):
60 | brightness=config["neopixel"]["brightness"]
61 | if neostrip[neopixel]!=(0,0,0):
62 | neostrip[neopixel]=(0,0,0)
63 | else:
64 | if color in config['colors']:
65 | final_color=[]
66 | for sub_color in config['colors'][color]:
67 | new_sub_color=int(sub_color*(brightness/100))
68 | if new_sub_color<0:
69 | new_sub_color=sub_color
70 | final_color.append(new_sub_color)
71 | neostrip[neopixel]=tuple(final_color)
72 | neostrip.write()
73 | def color_neostrip(neostrip,color,pixel_count):
74 | if color in config['colors']:
75 | for intcounter in range(pixel_count):
76 | neostrip[intcounter]=config['colors'][color]
77 | neostrip.write()
78 | def clear_neostrip(neostrip):
79 | neostrip.fill=(config['colors']['nocolor'])
80 | neostrip.write()
81 | def main_logic():
82 | global display
83 | global blndisplay
84 | if blndisplay:
85 | try:
86 | i2c=machine.I2C(scl=machine.Pin(config['screen']['sda']),sda=machine.Pin(config['screen']['scl']))
87 | display=ssd1306.SSD1306_I2C(config['screen']['width'],config['screen']['height'],i2c)
88 | clear_display()
89 | except OSError:
90 | print("Error trying to initialize the code for the OLED")
91 | blndisplay=False
92 | display=None
93 | button_ul=machine.Pin(config['button_ul']['pin'],machine.Pin.IN,machine.Pin.PULL_UP)
94 | button_ur=machine.Pin(config['button_ur']['pin'],machine.Pin.IN,machine.Pin.PULL_UP)
95 | button_dl=machine.Pin(config['button_dl']['pin'],machine.Pin.IN,machine.Pin.PULL_UP)
96 | button_dr=machine.Pin(config['button_dr']['pin'],machine.Pin.IN,machine.Pin.PULL_UP)
97 | neostrip=neopixel.NeoPixel(machine.Pin(config['neopixel']['pin']),config['neopixel']['count'])
98 | clear_neostrip(neostrip)
99 | colors=config["colors"]
100 | while True:
101 | if(button_ul.value()==0):
102 | print("Got 'button_ul' pressed.")
103 | lapse_time(neostrip,25,"red","POMODORO")
104 | lapse_time(neostrip,5,"green","FREE TIME")
105 | elif(button_ur.value()==0):
106 | print("Got 'button_ur' pressed.")
107 | for color in colors:
108 | color_neostrip(neostrip,color,config['neopixel']['count'])
109 | time.sleep(0.5)
110 | color_neostrip(neostrip,'nocolor',config['neopixel']['count'])
111 | elif(button_dl.value()==0):
112 | print("Got 'button_dl' pressed.")
113 | for color in colors:
114 | slow_fill_color(neostrip,colors,color,config['neopixel']['count'])
115 | time.sleep_ms(100)
116 | color_neostrip(neostrip,'nocolor',config['neopixel']['count'])
117 | elif(button_dr.value()==0):
118 | print("Got 'button_dr' pressed.")
119 | for i in range(0,config['neopixel']['count']):
120 | color=[get_random_int(),get_random_int(),get_random_int()]
121 | print(color)
122 | neostrip[i]=color
123 | time.sleep_ms(25)
124 | neostrip.write()
125 | time.sleep_ms(100)
126 | color_neostrip(neostrip,'nocolor',config['neopixel']['count'])
127 |
--------------------------------------------------------------------------------
/projects/problem_solver/README.md:
--------------------------------------------------------------------------------
1 | # MicroProblemSolver
2 |
3 | This is a script that is used to implement the Rubber duck debugging Technique asking questions so by this it will be forcing themselves (programmers) to explain it, line-by-line, to the duck.
4 |
5 | This uses the OLED LCD display on the board to show the question being asked so the problem can be somehow solved, this questions are taken randomly from the `questions.json` file in the repository that needs to be uploaded into the board.
6 |
7 | What we need to do is download all the code from the **`Release`** folder so it will be executed after booting up.
8 |
9 | So in the board you'll have the following files:
10 |
11 | - `main.py` (Renamed `problem_solver.py` file without comments.)
12 | - `questions.json` (File with questions that can be change or even add more.)
13 |
14 | Once all files are in the board, every time you want a random question you just need to reset the board.
15 |
16 | ## Parts needed:
17 |
18 | - **ESP8266**
19 |
20 | I'm using the Wemos D1 Mini board.
21 |
22 |
23 |
24 |
25 |
26 | - **OLED display (I2C)**
27 |
28 |
29 |
30 |
31 |
32 | ## Useful links:
33 |
34 | [Rubber duck debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging)
35 |
36 | ## TO DO:
37 |
38 | - [ ] Add real execution image.
39 |
40 | - [ ] Better documentation.
41 |
--------------------------------------------------------------------------------
/projects/problem_solver/code/problem_solver.py:
--------------------------------------------------------------------------------
1 | import json
2 | import time
3 | import urandom
4 | import ssd1306
5 | import machine
6 |
7 |
8 | def clear_display(fill=0, show=0):
9 | """
10 | This can be use either to clear the screen will all pixels activated or deactivated by changing
11 | the blnFill and if the show is set to one it will immediately shown on the OLED screen
12 |
13 | Args:
14 | fill: Boolean to fill the screen.
15 | show: Boolean to show or not on the screen.
16 |
17 | Returns:
18 | None.
19 | """
20 | display.fill(fill)
21 | if show:
22 | display.show()
23 |
24 |
25 | def wrapped_text(message, max_chars = 16):
26 | """
27 | It will split the text to fit the max_chars by line, by default is set to 16 but it could
28 | be changed.
29 |
30 | Args:
31 | message: String with the text to split.
32 |
33 | Returns:
34 | List with the text sliced.
35 | """
36 | words = message.split(" ")
37 | wordlines = []
38 | msg = ""
39 | for iteraction, word in enumerate(words):
40 | remaining_chars = max_chars - len(msg)
41 | if (len(msg + " " + word) <= remaining_chars) or ((len(word) + 1) <= remaining_chars):
42 | if iteraction == len(words) - 1:
43 | msg += word + " "
44 | wordlines.append(msg)
45 | break
46 | else:
47 | msg += word + " "
48 | else:
49 | if iteraction == len(words) - 1:
50 | wordlines.append(msg)
51 | msg = word + (" " * remaining_chars)
52 | wordlines.append(msg)
53 | break
54 | else:
55 | wordlines.append(msg)
56 | msg = word + " "
57 | if (len(msg) >= max_chars):
58 | wordlines.append(msg)
59 | msg = ""
60 | return wordlines
61 |
62 |
63 | def print_wrapped(words):
64 | """
65 | This will print the text into the screen display.
66 |
67 | Args:
68 | words: List with the text to print.
69 |
70 | Returns:
71 | None.
72 | """
73 | lines = [0, 8, 16, 24, 32, 40, 48]
74 | if len(words) <= len(lines):
75 | for item, message in enumerate(words):
76 | display.text(message, 0, lines[item])
77 | display.show()
78 | else:
79 | line_counter = 0
80 | for iteraction in range(len(words)):
81 | if iteraction >= len(lines):
82 | time.sleep(3)
83 | line_counter = 0
84 | display.text(words[iteraction], 0, lines[line_counter])
85 | display.show()
86 | line_counter += 1
87 |
88 |
89 | def get_random_question():
90 | """
91 | It will actually get a random number
92 |
93 | Returns:
94 | String with the question selected.
95 | """
96 | with open("questions.json", "r") as q_file:
97 | questions = json.loads(q_file.read())
98 | q_file.close()
99 |
100 | choise = urandom.getrandbits(5)
101 | return questions[str(choise)]
102 |
103 |
104 | i2c = machine.I2C(scl=machine.Pin(4), sda=machine.Pin(5))
105 | display = ssd1306.SSD1306_I2C(128, 64, i2c)
106 | clear_display()
107 |
108 |
109 | clear_display(1, 1)
110 | time.sleep_ms(100)
111 | clear_display(0, 1)
112 | print_wrapped(wrapped_text(get_random_question()))
113 | time.sleep(5)
114 | clear_display(1, 1)
115 | time.sleep_ms(200)
116 | clear_display(0, 1)
117 |
--------------------------------------------------------------------------------
/projects/problem_solver/code/questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "0":"Which person around you could help you?",
3 | "1":"Maybe you should consider refactoring?",
4 | "2":"Have you tried step by step execution?",
5 | "3":"Maybe some threads are unnecessary?",
6 | "4":"Maybe you turn it off and on again?",
7 | "5":"Could there be some race condition?",
8 | "6":"Where is the lacking print()?",
9 | "7":"Have you talked to your colleague?",
10 | "8":"Why not call for a group meeting?",
11 | "9":"Why not walk around your office?",
12 | "10":"Should you really be doing this?",
13 | "11":"Can the problem be broken down?",
14 | "12":"Have you tried to unit test it?",
15 | "13":"Maybe it is time for a coffee?",
16 | "14":"Have you tried a clean build?",
17 | "15":"Can you give me more details?",
18 | "16":"Can this be hardware related?",
19 | "17":"Could this not be your fault?",
20 | "18":"Is this actually a problem?",
21 | "19":"Can the code be simplified?",
22 | "20":"Have you tried googling it?",
23 | "21":"Maybe you can turn it on and off?",
24 | "22":"I am not sure try again!",
25 | "23":"Try again after having a coffee!",
26 | "24":"Walk around the office and try again!",
27 | "25":"Have you tried pair programming this?",
28 | "26":"Maybe some of the threads are unnecessary?",
29 | "27":"Can the problem be broken down more?",
30 | "28":"Call for a group meeting to discuss this!",
31 | "29":"Maybe you should consider some refactoring!",
32 | "30":"Have you tried googling it?",
33 | "31":"Why not try it again?"
34 | }
35 |
--------------------------------------------------------------------------------
/projects/problem_solver/release/problem_solver.py:
--------------------------------------------------------------------------------
1 | import json
2 | import time
3 | import urandom
4 | import ssd1306
5 | import machine
6 |
7 | def clear_display(fill=0, show=0):
8 | display.fill(fill)
9 | if show:
10 | display.show()
11 |
12 | def wrapped_text(message, max_chars=16):
13 | words = message.split(" ")
14 | wordlines = []
15 | msg = ""
16 | for iteraction, word in enumerate(words):
17 | remaining_chars = max_chars - len(msg)
18 | if (len(msg + " " + word) <= remaining_chars) or ((len(word) + 1) <= remaining_chars):
19 | if iteraction == len(words) - 1:
20 | msg += word + " "
21 | wordlines.append(msg)
22 | break
23 | else:
24 | msg += word + " "
25 | else:
26 | if iteraction == len(words) - 1:
27 | wordlines.append(msg)
28 | msg = word + (" " * remaining_chars)
29 | wordlines.append(msg)
30 | break
31 | else:
32 | wordlines.append(msg)
33 | msg = word + " "
34 | if (len(msg) >= max_chars):
35 | wordlines.append(msg)
36 | msg = ""
37 | return wordlines
38 |
39 | def print_wrapped(words):
40 | lines = [0, 8, 16, 24, 32, 40, 48]
41 | if len(words) <= len(lines):
42 | for item, message in enumerate(words):
43 | display.text(message, 0, lines[item])
44 | display.show()
45 | else:
46 | line_counter = 0
47 | for iteraction in range(len(words)):
48 | if iteraction >= len(lines):
49 | time.sleep(3)
50 | line_counter = 0
51 | display.text(words[iteraction], 0, lines[line_counter])
52 | display.show()
53 | line_counter += 1
54 |
55 | def get_random_question():
56 | with open("questions.json", "r") as q_file:
57 | questions = json.loads(q_file.read())
58 | q_file.close()
59 |
60 | choise = urandom.getrandbits(5)
61 | return questions[str(choise)]
62 |
63 | i2c = machine.I2C(scl=machine.Pin(4), sda=machine.Pin(5))
64 | display = ssd1306.SSD1306_I2C(128, 64, i2c)
65 | clear_display()
66 | clear_display(1, 1)
67 | time.sleep_ms(100)
68 | clear_display(0, 1)
69 | print_wrapped(wrapped_text(get_random_question()))
70 | time.sleep(5)
71 | clear_display(1, 1)
72 | time.sleep_ms(200)
73 | clear_display(0, 1)
74 |
--------------------------------------------------------------------------------
/projects/problem_solver/release/questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "0":"Which person around you could help you?",
3 | "1":"Maybe you should consider refactoring?",
4 | "2":"Have you tried step by step execution?",
5 | "3":"Maybe some threads are unnecessary?",
6 | "4":"Maybe you turn it off and on again?",
7 | "5":"Could there be some race condition?",
8 | "6":"Where is the lacking print()?",
9 | "7":"Have you talked to your colleague?",
10 | "8":"Why not call for a group meeting?",
11 | "9":"Why not walk around your office?",
12 | "10":"Should you really be doing this?",
13 | "11":"Can the problem be broken down?",
14 | "12":"Have you tried to unit test it?",
15 | "13":"Maybe it is time for a coffee?",
16 | "14":"Have you tried a clean build?",
17 | "15":"Can you give me more details?",
18 | "16":"Can this be hardware related?",
19 | "17":"Could this not be your fault?",
20 | "18":"Is this actually a problem?",
21 | "19":"Can the code be simplified?",
22 | "20":"Have you tried googling it?",
23 | "21":"Maybe you can turn it on and off?",
24 | "22":"I am not sure try again!",
25 | "23":"Try again after having a coffee!",
26 | "24":"Walk around the office and try again!",
27 | "25":"Have you tried pair programming this?",
28 | "26":"Maybe some of the threads are unnecessary?",
29 | "27":"Can the problem be broken down more?",
30 | "28":"Call for a group meeting to discuss this!",
31 | "29":"Maybe you should consider some refactoring!",
32 | "30":"Have you tried googling it?",
33 | "31":"Why not try it again?"
34 | }
35 |
--------------------------------------------------------------------------------
/projects/script_console/README.md:
--------------------------------------------------------------------------------
1 | # MicroScriptConsole
2 |
3 | This converts your ESP8266 board into a console where you can execute all script on the board. It will look all the `.py` files on the filesystem except for the `boot.py`, `main.py` and the `console.py`.
4 |
5 | Everything is based on the `console.py` which is a wrapper for the `ssd1306` module for the display and a `keypad` class for the button so we can navigate on the system and use the buttons to operate the **"MicroScriptConsole"**.
6 |
7 | What we need to do is download all the code from the **`Release`** folder so it will be executed after booting up.
8 |
9 | **UPDATE:**
10 |
11 | - [**2018-10-26**]
12 |
13 | I have finally generated the firmware for the ESP8266, so if you get the firmware flash onto the board and then get the all the code from the **`Release`** folder (Except for the `console.py`) and then name the `menu.py` to `main.py` so it will be executed after booting up.
14 |
15 | I have also added the `wifi_scanner.py` as a new script :smiley: !
16 |
17 | To get the firmware go to the [firmware](firmware) folder and get the latest built.
18 |
19 | - [**2018-10-30**]
20 |
21 | I have ported the Conway's Game of Life from [Mike Causer](https://github.com/mcauser) to work with the `SSD1306` Oled display.
22 |
23 | With the new [firmware](firmware) created it really works better than I expected, it saves more memory and I can run the script with ease. I will add more functionalities to the script to manage WiFi so everything is located within the same script.
24 |
25 | ## Parts needed:
26 |
27 | - **ESP8266**
28 |
29 | I'm using the Wemos D1 Mini board.
30 |
31 |
32 |
33 |
34 |
35 | - **OLED display (I2C)**
36 |
37 |
38 |
39 |
40 |
41 | - **Push buttons**
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | ---
50 |
51 | # Scripts ported / added:
52 |
53 | ## **`show_images.py`**
54 |
55 | Script to show images on the screen, these images are converted into hexadecimal text with an application which is called [The Dot Factory application](http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/) and the process on how to make it from a `.png` file is quite straight forward.
56 |
57 | Simply convert the `.png` image into `.bmp` extension with the software you prefer and then use the application to convert the `.bmp` into text.
58 |
59 | You can also find the software on the `other_tools` folder, click [here](other_tools/) to go the folder.
60 |
61 | Link to documented code
62 |
63 | [Link to documented code](code/scripts/show_images.py)
64 |
65 | #### **Execution images**
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | ## **`rubber_duck_debugging.py`**
75 |
76 | This is an implementation of the MicroProblemSolver script described [here](https://github.com/yeyeto2788/MicroPythonScripts/tree/master/MicroProblemSolver).
77 |
78 | ## **`simple_test.py`**
79 |
80 | This is just a simple script that prints a text and the count of the button presses on the screen.
81 |
82 | [Link to documented code](code/scripts/simple_test.py)
83 |
84 | #### **Execution images**
85 |
86 |
87 |
88 |
89 |
90 | ## **`magic8_ball.py`**
91 |
92 | Seeking for an advice to make a decision? This script is based on the [Magic 8-Ball](https://en.wikipedia.org/wiki/Magic_8-Ball) toy which was used for "fortune-telling"
93 |
94 | [Link to documented code](code/scripts/magic8_ball.py)
95 |
96 | ## **`I2C_scanner.py`**
97 |
98 | This script will scan all connected devices on the board to the I2C bus retrieving the HEX address and the decimal.
99 |
100 | Take into account that if the OLED screen is connected this will also show the address of it, normally the address is `0x3D`.
101 |
102 | [Link to documented code](code/scripts/I2C_scanner.py)
103 |
104 | ## **`wifi_scanner.py`**
105 |
106 | This script will scan all available WiFi networks on the area and it will output the `strength`, `chanel`, `name`, and `authmode` of them
107 |
108 | [Link to documented code](code/scripts/wifi_scanner.py)
109 |
110 | ## **`conways_game_of_life.py`**
111 |
112 | This script is a zero-player game which emulates the cellular life creation.
113 |
114 | The script was taken from the repository of [Mike Causer](https://github.com/mcauser/MicroPython-ESP8266-Nokia-5110-Conways-Game-of-Life)
115 |
116 | More [info](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
117 |
118 | [Link to documented code](code/scripts/conways_game_of_life.py)
119 |
120 | ---
121 |
122 | ## Useful links:
123 |
124 | [Micropython forum](https://forum.micropython.org/viewtopic.php?f=16&t=4901&p=28154&hilit=oled+display#p28154)
125 | [The Dot Factory application](http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/)
126 |
127 | ---
128 |
129 | ## TO DO:
130 |
131 | - [ ] Add all real execution images.
132 |
133 | - [ ] Add all real execution videos.
134 |
135 | - [ ] Port code to ESP32 (If needed).
136 |
137 | - [x] Try to generate firmware with `console.py` module as frozen module.
138 |
139 | - [ ] Add documentation for `console.py` module.
140 |
141 | - [ ] **Scripts to be added:**
142 |
65 |
66 |
67 | """
68 | connection_count = 0
69 | angle = 0
70 | delay = 0
71 | count = 0
72 | while True:
73 | cl, addr = s.accept()
74 | print(connection_count, "connection on", addr)
75 | print("Free in: %d" % gc.mem_free())
76 | connection_count += 1
77 | cl_file = cl.makefile("rwb", 0)
78 | while True:
79 | h = cl_file.readline()
80 | print(h)
81 | if ANGLE_STRING in h:
82 | try:
83 | angle = int(h.split(ANGLE_STRING)[1].split(b'&')[0])
84 | STATE = STATES[1]
85 | except ValueError:
86 | angle=0
87 | if DELAY_STRING in h:
88 | try:
89 | delay = int(h.split(DELAY_STRING)[1].split(b"&")[0])
90 | except ValueError:
91 | delay=0
92 | if COUNT_STRING in h:
93 | try:
94 | count = int(h.split(COUNT_STRING)[1].split(b" ")[0])
95 | except ValueError:
96 | count=0
97 | if h == b"" or h == b"\r\n":
98 | break
99 | response = html % "\n".join(STATE)
100 | try:
101 | cl.sendall(response)
102 | except OSError as error:
103 | print("Error trying to send all information. %s" % error)
104 | pass
105 | cl.close()
106 | print("Free out: %d" % gc.mem_free())
107 | print("Got angle=%s, delay=%s and count=%s" % (str(angle), str(delay), str(count)))
108 | if angle > 0:
109 | move_n_degrees(angle, delay, count)
110 | angle = 0
111 | delay = 0
112 | count = 0
113 |
--------------------------------------------------------------------------------
/projects/turn_table/release/uln2003.py:
--------------------------------------------------------------------------------
1 | import time
2 | import machine
3 |
4 | LOW = 0
5 | HIGH = 1
6 | FULL_ROTATION = int(4075.7728395061727 / 8)
7 |
8 | HALF_STEP = [
9 | [LOW, LOW, LOW, HIGH],
10 | [LOW, LOW, HIGH, HIGH],
11 | [LOW, LOW, HIGH, LOW],
12 | [LOW, HIGH, HIGH, LOW],
13 | [LOW, HIGH, LOW, LOW],
14 | [HIGH, HIGH, LOW, LOW],
15 | [HIGH, LOW, LOW, LOW],
16 | [HIGH, LOW, LOW, HIGH],
17 | ]
18 |
19 | FULL_STEP = [
20 | [HIGH, LOW, HIGH, LOW],
21 | [LOW, HIGH, HIGH, LOW],
22 | [LOW, HIGH, LOW, HIGH],
23 | [HIGH, LOW, LOW, HIGH]
24 | ]
25 |
26 |
27 | class Command:
28 |
29 | def __init__(self, stepper, steps, direction=1):
30 | self.stepper = stepper
31 | self.steps = steps
32 | self.direction = direction
33 |
34 | class Driver:
35 |
36 | @staticmethod
37 | def run(commands):
38 | max_steps = sum([c.steps for c in commands])
39 | count = 0
40 | while count != max_steps:
41 | for command in commands:
42 | if command.steps > 0:
43 | command.stepper.step(1, command.direction)
44 | command.steps -= 1
45 | count += 1
46 |
47 | class Stepper:
48 |
49 | def __init__(self, mode, pin1, pin2, pin3, pin4, delay=2000):
50 | self.mode = mode
51 | self.pin1 = machine.Pin(pin1, machine.Pin.OUT)
52 | self.pin2 = machine.Pin(pin2, machine.Pin.OUT)
53 | self.pin3 = machine.Pin(pin3, machine.Pin.OUT)
54 | self.pin4 = machine.Pin(pin4, machine.Pin.OUT)
55 | self.delay = delay
56 | self.steps_per_rev = FULL_ROTATION
57 | self.current_position = 0
58 | self.reset()
59 |
60 | def step(self, step_count, direction=1):
61 | for x in range(step_count):
62 | for bit in self.mode[::direction]:
63 | self.pin1.value(bit[0])
64 | self.pin2.value(bit[1])
65 | self.pin3.value(bit[2])
66 | self.pin4.value(bit[3])
67 | time.sleep_us(self.delay)
68 | self.current_position += (direction * step_count)
69 |
70 | def rel_angle(self, angle):
71 | steps = int(angle / 360 * self.steps_per_rev)
72 | self.step(steps)
73 |
74 | def abs_angle(self, angle):
75 | steps = int(angle / 360 * self.steps_per_rev)
76 | steps -= self.current_position % self.steps_per_rev
77 | self.step(steps)
78 |
79 | def revolution(self, rev_count):
80 | self.step(rev_count * self.steps_per_rev)
81 |
82 | def set_step_delay(self, us):
83 | if us < 20:
84 | self.delay = 20
85 | else:
86 | self.delay = us
87 |
88 | def set_steps_per_revolution(self):
89 | self.steps_per_rev = int((360 / (5.625 / 64)) / len(self.mode))
90 |
91 | def reset(self):
92 | self.pin1.value(0)
93 | self.pin2.value(0)
94 | self.pin3.value(0)
95 | self.pin4.value(0)
96 | if self.current_position > 0:
97 | self.current_position = 0
98 |
--------------------------------------------------------------------------------
/projects/weather_display/README.md:
--------------------------------------------------------------------------------
1 | # MicroWeatherThing
2 |
3 | This script is used on the Wemos D1 mini running MicroPython port for the ESP8266.
4 |
5 | It connects to OpenWeatherMap API in order to get the current weather from a location and it shows the local Temperature and Humidity read from the DHT11 sensor.
6 |
7 | What we need to do is download all the code from the `release` folder and rename the `weather_thing.py` file to `main.py` so it will be executed after booting up.
8 |
9 | ## Parts needed:
10 |
11 | - **ESP8266**
12 |
13 | I'm using the Wemos D1 Mini board.
14 |
15 |
16 |
17 |
18 |
19 | - **OLED display (I2C)**
20 |
21 |
22 |
23 |
24 |
25 | - **DHT11 Humidity sensor.**
26 |
27 |
28 |
29 |
30 |
31 | ### TO DO:
32 |
33 | - [x] Add delay between execution for the DHT11 sensor and the calls done to the OpenWeatherMap API.
34 |
35 | - [x] Better documentation.
36 |
37 | - [ ] Add images.
38 |
- [ ] Execution images.
39 |
- [ ] Board setup images.
40 |
--------------------------------------------------------------------------------
/projects/weather_display/code/weather_thing.py:
--------------------------------------------------------------------------------
1 | import ssd1306
2 | import json
3 | import urequests
4 | import time
5 | import dht
6 | import machine
7 |
8 |
9 | def connect_wifi(ssid, pwd):
10 | """
11 | Function to connect to WIFI.
12 |
13 | Args:
14 | ssid: Name of the WIFI connection.
15 | pwd: Boolean for the connection.
16 |
17 | Returns:
18 | True if it's connected to wifi
19 |
20 | """
21 | import network
22 | sta_if = network.WLAN(network.STA_IF)
23 | if not sta_if.isconnected():
24 | display_msg('Connecting to network...', 8)
25 | sta_if.active(True)
26 | sta_if.connect(ssid, pwd)
27 | while not sta_if.isconnected():
28 | pass
29 | return True
30 |
31 |
32 | def get_weather(city, api_key):
33 | """
34 | This gets the current weather from the OpenWeatherMap API
35 |
36 | Args:
37 | city: City you want the weather from
38 | api_key: api_key: API Key from OpenWeatherMap
39 |
40 | Returns:
41 | Data retrieved from the API.
42 |
43 | """
44 | r = urequests.get(
45 | "http://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s" % (city, api_key)
46 | ).json()
47 | data = []
48 | min_temp = int(r["main"]["temp_min"] - 273.15)
49 | data.append("Min: %s C" % min_temp)
50 | max_temp = int(r["main"]["temp_max"] - 273.15)
51 | data.append("Max: %s C" % max_temp)
52 | actual_temp = int(r["main"]["temp"] - 273.15)
53 | data.append("Current: %s C" % actual_temp)
54 | humidity = int(r["main"]["humidity"])
55 | data.append("Humidity: %s" % humidity)
56 | condition = str(r["weather"][0]["description"])
57 | data.append("Condition: %s" % condition)
58 | return data
59 |
60 |
61 | def clear_display():
62 | """
63 | Display clear so no information will be shown.
64 |
65 | Returns:
66 | None.
67 |
68 | """
69 | display.fill(0)
70 |
71 |
72 | def display_msg(message, line, start=0):
73 | """
74 | Display the message on the screen.
75 |
76 | Args:
77 | message: String with the text that wants to be shown
78 | line: Line where you want the text
79 | start: Integer where the text will start to be printed
80 |
81 | Returns:
82 | None.
83 |
84 | """
85 | lines = [0, 8, 16, 24, 32, 40, 48]
86 | if line in lines:
87 | display.text(message, start, line)
88 |
89 |
90 | def draw_hline(x, y):
91 | """
92 | Draw a horizontal line on the screen
93 |
94 | Args:
95 | x: X pixel
96 | y: Y pixel
97 |
98 | Returns:
99 | None.
100 |
101 | """
102 | for i in range(0, x):
103 | display.pixel(i, y, 1)
104 |
105 |
106 | def draw_vline(x, y):
107 | """
108 | Draw a vertical line on the screen
109 |
110 | Args:
111 | x: X pixel
112 | y: Y pixel
113 |
114 | Returns:
115 | None.
116 |
117 | """
118 | for i in range(0, y):
119 | display.pixel(x, i, 1)
120 |
121 |
122 | def parse_weather_data(data):
123 | """
124 | Parse weather data from the GetWeather function and show the weather on the screen.
125 |
126 | Args:
127 | data: Array from the GetWeather function.
128 |
129 | Returns:
130 | None.
131 |
132 | """
133 | clear_display()
134 | for i in range(0, len(data)):
135 | if i < (len(data) - 1):
136 | display_msg(data[i], int(i * 8))
137 | else:
138 | final_line = data[i].split(": ")
139 | display_msg(final_line[0], 40)
140 | display_msg('{:^16}'.format(final_line[1]), 48)
141 | draw_hline(WIDTH, 37)
142 | display.show()
143 |
144 |
145 | def get_time():
146 | """
147 | Get local time from the internet.
148 |
149 | Returns:
150 | String with the time
151 |
152 | """
153 | import ntptime
154 | ntptime.settime()
155 | ts = time.localtime()
156 | year = ts[0]
157 | month = ts[1]
158 | day = ts[2]
159 | hour = ts[3]
160 | mins = ts[4]
161 | actual_time = "%s/%s/%s %s:%s" % (str(day), str(month), str(year), str(hour), str(mins))
162 | return actual_time
163 |
164 |
165 | def show_time():
166 | """
167 | This function will show the time on the OLED shield
168 |
169 | Returns:
170 | None.
171 |
172 | """
173 | clear_display()
174 | display_msg('{:^16}'.format("CLOCK"), 8)
175 | data = get_time().split(" ")
176 | display_msg('{:^16}'.format(data[0]), 32)
177 | display_msg('{:^16}'.format(data[1]), 40)
178 | display.show()
179 |
180 |
181 | def get_local_conditions():
182 | """
183 | This will get the time from the internet if the internet connection
184 | NOTE: take into account that this can give a time from the server which can be in other
185 | location.
186 |
187 | Returns:
188 | None.
189 |
190 | """
191 | clear_display()
192 | d = dht.DHT11(machine.Pin(4))
193 | display_msg('{:16}'.format("Local Temp:"), 16)
194 | display_msg('{:^16}'.format(str(d.temperature())), 24)
195 | display_msg('{:16}'.format("Local Humidity:"), 40)
196 | display_msg('{:^16}'.format(str(d.humidity())), 48)
197 | display.show()
198 |
199 |
200 | i2c = machine.I2C(scl=machine.Pin(4), sda=machine.Pin(5))
201 | WIDTH = 128
202 | HEIGHT = 64
203 | display = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)
204 |
205 | CITY = 'City you want the weather from'
206 | API_KEY = 'OpenWeatherAPI'
207 | SSID = 'Name of the WIFI connection'
208 | PWD = 'Wifi connection password'
209 |
210 | received_data = get_weather(CITY, API_KEY)
211 | start_time = time.ticks_ms() // 1000
212 |
213 | while connect_wifi(SSID, PWD):
214 | time_now = time.ticks_ms() // 1000
215 |
216 | if (time_now - start_time) < (3 * 60):
217 | show_time()
218 | time.sleep(30)
219 | get_local_conditions()
220 | time.sleep(30)
221 | parse_weather_data(received_data)
222 | time.sleep(30)
223 | else:
224 | received_data = get_weather(CITY, API_KEY)
225 | start_time = time.ticks_ms() // 1000
226 |
--------------------------------------------------------------------------------
/projects/weather_display/release/weather_thing.py:
--------------------------------------------------------------------------------
1 | import ssd1306
2 | import json
3 | import urequests
4 | import time
5 | import dht
6 | import machine
7 |
8 | def connect_wifi(ssid, pwd):
9 | import network
10 | sta_if = network.WLAN(network.STA_IF)
11 | if not sta_if.isconnected():
12 | display_msg('Connecting to network...', 8)
13 | sta_if.active(True)
14 | sta_if.connect(ssid, pwd)
15 | while not sta_if.isconnected():
16 | pass
17 | return True
18 |
19 | def get_weather(city, api_key):
20 | r = urequests.get(
21 | "http://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s" % (city, api_key)
22 | ).json()
23 | data = []
24 | min_temp = int(r["main"]["temp_min"] - 273.15)
25 | data.append("Min: %s C" % min_temp)
26 | max_temp = int(r["main"]["temp_max"] - 273.15)
27 | data.append("Max: %s C" % max_temp)
28 | actual_temp = int(r["main"]["temp"] - 273.15)
29 | data.append("Current: %s C" % actual_temp)
30 | humidity = int(r["main"]["humidity"])
31 | data.append("Humidity: %s" % humidity)
32 | condition = str(r["weather"][0]["description"])
33 | data.append("Condition: %s" % condition)
34 | return data
35 |
36 | def clear_display():
37 | display.fill(0)
38 |
39 | def display_msg(message, line, start=0):
40 | lines = [0, 8, 16, 24, 32, 40, 48]
41 | if line in lines:
42 | display.text(message, start, line)
43 |
44 | def draw_hline(x, y):
45 | for i in range(0, x):
46 | display.pixel(i, y, 1)
47 |
48 | def draw_vline(x, y):
49 | for i in range(0, y):
50 | display.pixel(x, i, 1)
51 |
52 | def parse_weather_data(data):
53 | clear_display()
54 | for i in range(0, len(data)):
55 | if i < (len(data) - 1):
56 | display_msg(data[i], int(i * 8))
57 | else:
58 | final_line = data[i].split(": ")
59 | display_msg(final_line[0], 40)
60 | display_msg('{:^16}'.format(final_line[1]), 48)
61 | draw_hline(WIDTH, 37)
62 | display.show()
63 |
64 | def get_time():
65 | import ntptime
66 | ntptime.settime()
67 | ts = time.localtime()
68 | year = ts[0]
69 | month = ts[1]
70 | day = ts[2]
71 | hour = ts[3]
72 | mins = ts[4]
73 | actual_time = "%s/%s/%s %s:%s" % (str(day), str(month), str(year), str(hour), str(mins))
74 | return actual_time
75 |
76 | def show_time():
77 | clear_display()
78 | display_msg('{:^16}'.format("CLOCK"), 8)
79 | data = get_time().split(" ")
80 | display_msg('{:^16}'.format(data[0]), 32)
81 | display_msg('{:^16}'.format(data[1]), 40)
82 | display.show()
83 |
84 | def get_local_conditions():
85 | clear_display()
86 | d = dht.DHT11(machine.Pin(4))
87 | display_msg('{:16}'.format("Local Temp:"), 16)
88 | display_msg('{:^16}'.format(str(d.temperature())), 24)
89 | display_msg('{:16}'.format("Local Humidity:"), 40)
90 | display_msg('{:^16}'.format(str(d.humidity())), 48)
91 | display.show()
92 |
93 | i2c = machine.I2C(scl=machine.Pin(4), sda=machine.Pin(5))
94 | WIDTH = 128
95 | HEIGHT = 64
96 | display = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)
97 | CITY = 'City you want the weather from'
98 | API_KEY = 'OpenWeatherAPI'
99 | SSID = 'Name of the WIFI connection'
100 | PWD = 'Wifi connection password'
101 | received_data = get_weather(CITY, API_KEY)
102 | start_time = time.ticks_ms() // 1000
103 |
104 | while connect_wifi(SSID, PWD):
105 | time_now = time.ticks_ms() // 1000
106 | if (time_now - start_time) < (3 * 60):
107 | show_time()
108 | time.sleep(30)
109 | get_local_conditions()
110 | time.sleep(30)
111 | parse_weather_data(received_data)
112 | time.sleep(30)
113 | else:
114 | received_data = get_weather(CITY, API_KEY)
115 | start_time = time.ticks_ms() // 1000
116 |
--------------------------------------------------------------------------------
/projects/weather_station/README.md:
--------------------------------------------------------------------------------
1 | # MicroWeatherStation
2 |
3 | This script will read the sensor DHT11 data and it will create a simple server so the data is shown on a web page.
4 |
5 | ### Image of code running on the Wemos D1 mini board:
6 |
7 |
8 |
9 |
10 |
11 | ## Parts needed:
12 |
13 | - ESP8266
14 |
15 | I'm using the Wemos D1 Mini board.
16 |
17 |
18 |
19 |
20 |
21 | - DHT11 Sensor
22 |
23 |
24 |
25 |
26 |
27 | ## NOTE:
28 |
29 | Take into account that I'm using a Wemos D1 mini and it's DHT11 shield, so in the script you'll see the **`d = dht.DHT11(machine.Pin(2))`** and in the example page of the Micropython documentation they use other pin (4).
30 |
31 | ### TO DO:
32 |
33 | - [ ] Better documentation.
34 |
35 | - [x] Add execution images.
36 |
--------------------------------------------------------------------------------
/projects/weather_station/code/weather_station.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import dht
3 | import gc
4 | import machine
5 |
6 |
7 | def read_sensors():
8 | """
9 | Read the DHT11 sensor's Temperature and Humidity
10 |
11 | Returns:
12 | Array with the temperature and the humidity read from the sensor.
13 | """
14 | data = []
15 | d = dht.DHT11(machine.Pin(2))
16 | d.measure()
17 | temperature = d.temperature()
18 | humidity = d.humidity()
19 | for i in range(0, 1):
20 | data.append('
%s C
%s %
' % (str(temperature), str(humidity)))
21 | return data
22 |
23 |
24 | def main():
25 | """
26 | Main code to be executed, all logic is within this function.
27 |
28 | Returns:
29 | None
30 | """
31 | html = b"""
32 |
33 |
34 | Weather Station
35 |
36 |
37 |
38 |
47 |
48 |
49 |
50 |
51 |
ESP8266 Weather Station
52 |
53 |
54 |
55 |
Temperature
Humidity
%s
56 |
57 |
NOTE: This page will automatically refresh every 30 seconds.
NOTE: This page will automatically refresh every 30 seconds.
44 |
45 |
58 |
59 |
60 | """
61 | addr = socket.getaddrinfo('192.168.4.1', 80)[0][-1]
62 | s = socket.socket()
63 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
64 | s.bind(addr)
65 | s.listen(5)
66 |
67 | while True:
68 | cl, addr = s.accept()
69 | print('Client connected from', addr)
70 | print("Free in: %d" % gc.mem_free())
71 | cl_file = cl.makefile('rwb', 0)
72 | while True:
73 | h = cl_file.readline()
74 | if h == b"" or h == b"\r\n":
75 | break
76 | rows = read_sensors()
77 | response = html % '\n'.join(rows)
78 | try:
79 | cl.sendall(response)
80 | except OSError as error:
81 | print("Error trying to send all information. %s" % error)
82 | pass
83 | cl.close()
84 |
85 | main()
86 |
--------------------------------------------------------------------------------
/projects/wifi_scan/README.md:
--------------------------------------------------------------------------------
1 | # MicroWiFiScan
2 |
3 | This script is used on the NODEMCU Wemos Wifi running MicroPython port for the ESP8266.
4 |
5 | It scans all available networks, it will show the strength, name and security of the WiFi available connections.
6 |
7 | What we need to do is download all the code from the `Relase` folder, upload the `wifi_scan.py` to the board and you do one of the following things:
8 |
9 | - Upload also the `main.py` so it will be executed after booting up.
10 |
11 | - Creating your own `main.py` script so it does more than the one on the folder (just scan and show available connections).
12 |
13 | ## Parts needed:
14 |
15 | - ESP8266.
16 |
17 | - OLED display (I2C).
18 |
19 | ### TO DO:
20 |
21 | - [ ] Better documentation.
22 |
23 | - [ ] Add images.
24 |
- [ ] Execution images.
25 |
- [ ] Board setup images.
26 |
--------------------------------------------------------------------------------
/projects/wifi_scan/code/wifi_scan.py:
--------------------------------------------------------------------------------
1 | import network
2 | import machine
3 | import ssd1306
4 | import utime
5 | import gc
6 | gc.enable()
7 |
8 |
9 | class WiFiScanner:
10 | def __init__(self, sda_pin=5, scl_pin=4):
11 | """
12 | Initialize the function with the pins 5,4 (sda, scl respectively) by default.
13 |
14 | In this function we initialize the i2c bus and the screen and activate WiFi radio.
15 |
16 | Args:
17 | sda_pin: integer with the pin number assigned for SDA
18 | scl_pin: integer with the pin number assigned for SCL
19 | """
20 | self.sda_pin = sda_pin
21 | self.scl_pin = scl_pin
22 | self.name = ''
23 | self.strength = ''
24 | self.status = ''
25 | self.kanaal = ''
26 | self.i2c = machine.I2C(scl=machine.Pin(self.scl_pin), sda=machine.Pin(self.sda_pin))
27 | self.oled = ssd1306.SSD1306_I2C(128, 64, self.i2c)
28 | self.oled.fill(1)
29 | self.oled.show()
30 | self.wlan = network.WLAN(network.STA_IF)
31 | self.wlan.active(True)
32 |
33 | def format(self):
34 | """
35 | Try to do a WiFi available connections and than format the text that will be display on the
36 | screen.
37 |
38 | If WiFi scan fails the display will show NONE on the entire segments of the screen.
39 |
40 | Returns:
41 | None.
42 | """
43 | try:
44 | wlan_list = self.wlan.scan()
45 | except:
46 | wlan_list = [['NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE']]
47 | for counter in wlan_list:
48 | self.name = str(counter[0], 'utf8')
49 | self.strength = str(counter[3]) + ' dBm'
50 | self.kanaal = 'Channel: ' + str(counter[2])
51 | self.status = self.get_secure(counter[4])
52 | self.show_display()
53 | self.oled.fill(0)
54 | self.oled.show()
55 |
56 | @staticmethod
57 | def get_secure(num):
58 | """
59 | Convert the number returned by the Wifi scan to a test showing what type of
60 | Wifi security it is.
61 |
62 | If the number is not recognized it will just return the number as a string.
63 |
64 | Args:
65 | num: integer with the type of security.
66 |
67 | Returns:
68 | String with the description of the Wifi security.
69 | """
70 | s_return = ""
71 | try:
72 | if int(num) == 0:
73 | s_return = 'Open wifi'
74 | elif int(num) == 1:
75 | s_return = 'WEP'
76 | elif int(num) ==2:
77 | s_return = 'WPA-PSK'
78 | elif int(num) == 3:
79 | s_return = 'WPA2-PSK'
80 | elif int(num) == 4:
81 | s_return = 'WPA/WPA2-PSK'
82 | else:
83 | s_return = str(num)
84 |
85 | return s_return
86 | except:
87 | return s_return
88 |
89 | def show_display(self):
90 | """
91 | Cleans the screen and show all data.
92 |
93 | If network names are longer than the display's width it will split the name in two
94 | and show it will be shown on row 1,2.
95 |
96 | Returns:
97 | None.
98 | """
99 |
100 | self.oled.fill(0)
101 | self.oled.show()
102 | if len(self.name) > 15:
103 | self.oled.text(self.name[0:15], 0, 0)
104 | self.oled.text(self.name[15:int(len(self.name))], 0, 8)
105 | else:
106 | self.oled.text(self.name, 0, 0)
107 | self.oled.text(self.strength, 30, 20)
108 | self.oled.text(self.status, 30, 30)
109 | self.oled.text(self.kanaal, 30, 40)
110 | self.oled.text((str(gc.mem_free()) + " B"), 30, 50)
111 | self.oled.show()
112 | utime.sleep_ms(10000)
113 |
114 | def __str__(self):
115 | return "Name: {}.\n{}\n{}.\n{}.".format(self.name, self.strength, self.kanaal, self.status)
116 |
--------------------------------------------------------------------------------
/projects/wifi_scan/release/boot.py:
--------------------------------------------------------------------------------
1 | import webrepl
2 | import wifi_scan
3 | webrepl.start()
4 |
5 | display = wifi_scan.WiFiScanner(5, 4)
6 | while True:
7 | display.format()
8 |
9 | #Uncomment code below to see the output on the REPL or WebREPL
10 | #print(display)
11 |
--------------------------------------------------------------------------------
/projects/wifi_scan/release/wifi_scan.py:
--------------------------------------------------------------------------------
1 | import network
2 | import machine
3 | import ssd1306
4 | import utime
5 | import gc
6 | gc.enable()
7 |
8 |
9 | class WiFiScanner:
10 | def __init__(self, sda_pin=5, scl_pin=4):
11 |
12 | self.sda_pin = sda_pin
13 | self.scl_pin = scl_pin
14 | self.name = ''
15 | self.strength = ''
16 | self.status = ''
17 | self.kanaal = ''
18 | self.i2c = machine.I2C(scl=machine.Pin(self.scl_pin), sda=machine.Pin(self.sda_pin))
19 | self.oled = ssd1306.SSD1306_I2C(128, 64, self.i2c)
20 | self.oled.fill(1)
21 | self.oled.show()
22 | self.wlan = network.WLAN(network.STA_IF)
23 | self.wlan.active(True)
24 |
25 | def format(self):
26 |
27 | try:
28 | wlan_list = self.wlan.scan()
29 | except:
30 | wlan_list = [['NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE']]
31 | for counter in wlan_list:
32 | self.name = str(counter[0], 'utf8')
33 | self.strength = str(counter[3]) + ' dBm'
34 | self.kanaal = 'Channel: ' + str(counter[2])
35 | self.status = self.get_secure(counter[4])
36 | self.show_display()
37 | self.oled.fill(0)
38 | self.oled.show()
39 |
40 | @staticmethod
41 | def get_secure(num):
42 |
43 | s_return = ""
44 | try:
45 | if int(num) == 0:
46 | s_return = 'Open wifi'
47 | elif int(num) == 1:
48 | s_return = 'WEP'
49 | elif int(num) ==2:
50 | s_return = 'WPA-PSK'
51 | elif int(num) == 3:
52 | s_return = 'WPA2-PSK'
53 | elif int(num) == 4:
54 | s_return = 'WPA/WPA2-PSK'
55 | else:
56 | s_return = str(num)
57 |
58 | return s_return
59 | except:
60 | return s_return
61 |
62 | def show_display(self):
63 |
64 |
65 | self.oled.fill(0)
66 | self.oled.show()
67 | if len(self.name) > 15:
68 | self.oled.text(self.name[0:15], 0, 0)
69 | self.oled.text(self.name[15:int(len(self.name))], 0, 8)
70 | else:
71 | self.oled.text(self.name, 0, 0)
72 | self.oled.text(self.strength, 30, 20)
73 | self.oled.text(self.status, 30, 30)
74 | self.oled.text(self.kanaal, 30, 40)
75 | self.oled.text((str(gc.mem_free()) + " B"), 30, 50)
76 | self.oled.show()
77 | utime.sleep_ms(10000)
78 |
79 | def __str__(self):
80 | return "Name: {}.\n{}\n{}.\n{}.".format(self.name, self.strength, self.kanaal, self.status)
81 |
--------------------------------------------------------------------------------
/snippets/connect_wifi.py:
--------------------------------------------------------------------------------
1 | import time
2 | import network
3 |
4 | ssid_ = '<#your_ssid#>'
5 | wp2_pass = '<#your_wpa2_pass#>'
6 |
7 |
8 | def do_connect(retries=5):
9 | sta_if = network.WLAN(network.STA_IF)
10 | if not sta_if.isconnected():
11 | print('connecting to network...')
12 | sta_if.active(True)
13 | sta_if.connect(ssid_, wp2_pass)
14 | while not sta_if.isconnected() and retries <= 5:
15 | print("Executing code in '{}' seconds.".format(retries))
16 | if retries < 0:
17 | break
18 | else:
19 | time.sleep(1)
20 | retries -= 1
21 | pass
22 | print('network config:', sta_if.ifconfig())
23 |
24 |
25 | # connecting to WiFi
26 | do_connect()
27 |
--------------------------------------------------------------------------------
/snippets/mqtt_publish.py:
--------------------------------------------------------------------------------
1 | """This need the module umqttsimple which comes from
2 | https://raw.githubusercontent.com/micropython/micropython-lib/master/umqtt.simple/umqtt/simple.py
3 | """
4 | import machine
5 | import ubinascii
6 | from umqttsimple import MQTTClient, MQTTException
7 |
8 | HOST = "<#your_broker_ip#>"
9 | USER = "<#your_user#>"
10 | PASSWORD = "<#your_password#>"
11 |
12 |
13 | def publish_message(topic, msg):
14 | """Publish a message to a broker.
15 |
16 | If connection is not possible it will not publish any message.
17 | """
18 | broker = MQTTClient(
19 | ubinascii.hexlify(machine.unique_id()),
20 | server=HOST,
21 | user=USER,
22 | password=PASSWORD)
23 | try:
24 | broker.connect()
25 | except (MQTTException, OSError):
26 | print("Error occurred connecting to broker.")
27 | broker = None
28 |
29 | if broker is not None:
30 | broker.publish(topic.encode(), msg.encode())
31 | broker.disconnect()
32 |
--------------------------------------------------------------------------------
/snippets/ntp_time.py:
--------------------------------------------------------------------------------
1 | """You need to be connected to internet in order to execute the request"""
2 | import machine
3 | import ntptime
4 |
5 | ntptime.host = "es.pool.ntp.org"
6 |
7 | try:
8 | ntptime.settime()
9 | except OSError:
10 | print('ERROR: Cannot set time via ntp')
11 |
12 | rtc = machine.RTC()
13 | print(rtc.datetime())
14 |
--------------------------------------------------------------------------------
/static/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: white;
3 | }
4 |
5 | h1 {
6 | font-family: Lucida Console;
7 | color: black;
8 | text-align: center;
9 | }
10 |
11 | h3 {
12 | font-family: Lucida Console;
13 | color: black;
14 | text-align: center;
15 | }
16 |
17 | table {
18 | table-layout: center;
19 | width: 60%;
20 | font-family: Lucida Console;
21 | color: gray;
22 | }
23 |
24 | th {
25 | font-style: bold;
26 | text-align: center;
27 | height: 15px;
28 | border-bottom: 1px solid #ddd;
29 | padding: 5px
30 | }
31 |
32 | td {
33 | border-bottom: 1px solid #ddd;
34 | }
35 |
36 | form {
37 | text-align: center;
38 | }
39 |
40 | input[type=text] {
41 | text-align: center;
42 | width: 60%;
43 | padding: 12px 20px;
44 | margin: 8px 0;
45 | box-sizing: border-box;
46 | font-family: Lucida Console;
47 | }
48 |
49 | input[type=button], input[type=submit], input[type=reset] {
50 | width: 60%;
51 | font-style: bold;
52 | background-color: #ddd;
53 | border: none;
54 | color: black;
55 | padding: 16px 32px;
56 | text-decoration: none;
57 | margin: 4px 2px;
58 | cursor: pointer;
59 | }
--------------------------------------------------------------------------------
/static/html/CSS_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Reading the file!
7 |
34 |
35 |
36 |