├── .gitignore ├── .pylintrc ├── README.md ├── modules ├── uln2003 │ ├── README.md │ ├── code │ │ └── uln2003.py │ ├── docs │ │ └── images │ │ │ ├── 28BYJ-48-Pinout-Wirings.png │ │ │ ├── 28BYJ-48-Stepper-Motor.jpg │ │ │ ├── wemos_d1_mini.png │ │ │ └── wemos_pinout.jpg │ ├── examples │ │ └── StepperTest.py │ └── release │ │ └── uln2003.py └── witty_utils │ ├── README.md │ ├── code │ └── witty_utils.py │ ├── examples │ └── pomodoro.py │ └── release │ └── witty_utils.py ├── projects ├── bulleting_board │ ├── README.md │ ├── code │ │ └── bulleting_board.py │ └── release │ │ └── bulleting_board.py ├── camera_slider │ ├── README.md │ ├── code │ │ └── camera_slider.py │ └── release │ │ └── camera_slider.py ├── micro_server │ ├── README.md │ ├── code │ │ ├── index.html │ │ └── micro_server.py │ └── release │ │ └── micro_server.py ├── pomodoro │ ├── README.md │ ├── code │ │ ├── config.json │ │ └── pomodoro.py │ ├── docs │ │ ├── images │ │ │ ├── v01_pomodoro_pcb_top.png │ │ │ ├── v01_pomodoro_pcb_top_placement.png │ │ │ ├── v02_pomodoro_pcb_bottom.png │ │ │ └── v02_pomodoro_pcb_top.png │ │ └── pdf │ │ │ └── schematics_v02.pdf │ ├── hardware │ │ ├── 01 │ │ │ ├── MicroPomodoro.brd │ │ │ └── MicroPomodoro.sch │ │ └── 02 │ │ │ ├── 3D_Case │ │ │ ├── STL │ │ │ │ └── uPomodoro Case.stl │ │ │ └── uPomodoro Case.f3z │ │ │ └── PCB │ │ │ ├── MicroPomodoro.brd │ │ │ └── MicroPomodoro.sch │ └── release │ │ ├── PCB │ │ └── v0.1 │ │ │ ├── MicroPomodoro.brd │ │ │ ├── MicroPomodoro.sch │ │ │ └── MicroPomodoro_schematics.pdf │ │ ├── boot.py │ │ ├── config.json │ │ └── pomodoro.py ├── problem_solver │ ├── README.md │ ├── code │ │ ├── problem_solver.py │ │ └── questions.json │ └── release │ │ ├── problem_solver.py │ │ └── questions.json ├── script_console │ ├── README.md │ ├── code │ │ ├── console.py │ │ ├── menu.py │ │ └── scripts │ │ │ ├── I2C_scanner.py │ │ │ ├── conways_game_of_life.py │ │ │ ├── img │ │ │ ├── MSC_logo.txt │ │ │ ├── github_logo.txt │ │ │ ├── python_logo.txt │ │ │ ├── upython_logo.txt │ │ │ └── upython_logo_s.txt │ │ │ ├── magic8_ball.py │ │ │ ├── message_board.py │ │ │ ├── rubber_duck_debugging.py │ │ │ ├── show_images.py │ │ │ ├── simple_test.py │ │ │ └── wifi_scanner.py │ ├── firmware │ │ └── script_console_0001.bin │ ├── hardware │ │ └── 01 │ │ │ ├── KeyPad.fzz │ │ │ ├── KeyPad_bom.html │ │ │ ├── gerber │ │ │ ├── KeyPad_contour.gm1 │ │ │ ├── KeyPad_copperBottom.gbl │ │ │ ├── KeyPad_drill.txt │ │ │ ├── KeyPad_maskBottom.gbs │ │ │ ├── KeyPad_pasteMaskBottom.gbp │ │ │ ├── KeyPad_pnp.txt │ │ │ ├── KeyPad_silkBottom.gbo │ │ │ └── KeyPad_silkTop.gto │ │ │ ├── images │ │ │ ├── KeyPad_pcb.pdf │ │ │ └── KeyPad_pcb.png │ │ │ └── pdf │ │ │ ├── KeyPad_etch_copper_bottom.pdf │ │ │ ├── KeyPad_etch_copper_bottom_mirror.pdf │ │ │ ├── KeyPad_etch_mask_bottom.pdf │ │ │ ├── KeyPad_etch_mask_bottom_mirror.pdf │ │ │ ├── KeyPad_etch_paste_mask_bottom.pdf │ │ │ ├── KeyPad_etch_paste_mask_bottom_mirror.pdf │ │ │ ├── KeyPad_etch_silk_bottom.pdf │ │ │ ├── KeyPad_etch_silk_bottom_mirror.pdf │ │ │ ├── KeyPad_etch_silk_top.pdf │ │ │ └── KeyPad_etch_silk_top_mirror.pdf │ ├── other_tools │ │ ├── TheDotFactory-0.1.4.7z │ │ ├── images │ │ │ └── bmp │ │ │ │ ├── micro_console.bmp │ │ │ │ ├── python.bmp │ │ │ │ ├── upython_m.bmp │ │ │ │ └── upython_s.bmp │ │ └── ring_tones.txt │ └── release │ │ ├── console.py │ │ ├── menu.py │ │ └── scripts │ │ ├── I2C_scanner.py │ │ ├── conways_game_of_life.py │ │ ├── img │ │ ├── MSC_logo.txt │ │ ├── github_logo.txt │ │ ├── python_logo.txt │ │ ├── upython_logo.txt │ │ └── upython_logo_s.txt │ │ ├── magic8_ball.py │ │ ├── message_board.py │ │ ├── rubber_duck_debugging.py │ │ ├── show_images.py │ │ ├── simple_test.py │ │ └── wifi_scanner.py ├── turn_table │ ├── README.md │ ├── code │ │ ├── main.py │ │ └── uln2003.py │ └── release │ │ ├── main.py │ │ └── uln2003.py ├── weather_display │ ├── README.md │ ├── code │ │ └── weather_thing.py │ └── release │ │ └── weather_thing.py ├── weather_station │ ├── README.md │ ├── code │ │ └── weather_station.py │ └── release │ │ └── weather_station.py └── wifi_scan │ ├── README.md │ ├── code │ └── wifi_scan.py │ └── release │ ├── boot.py │ └── wifi_scan.py ├── snippets ├── connect_wifi.py ├── mqtt_publish.py └── ntp_time.py ├── static ├── css │ └── style.css ├── html │ ├── CSS_index.html │ └── index.html └── images │ ├── 12_neopixel_ring.png │ ├── DHT11.png │ ├── bulleting_board_index.png │ ├── d-duino-pins.png │ ├── dht11.png │ ├── photos │ ├── msc_oled.png │ ├── print_test.png │ ├── python_oled.png │ ├── upython_oled.png │ ├── upython_oled_s.png │ ├── wifi_scan1.jpg │ ├── wifi_scan2.jpg │ └── wifi_scan3.jpg │ ├── push_button.png │ ├── weather_station_index.png │ ├── wemos_d1_mini.png │ ├── wemos_mini_oled.png │ ├── wemos_pinout.jpg │ ├── witty-cloud.jpg │ └── witty-schematics.jpg └── tools ├── README.md ├── generate_releases.py ├── requirements.txt └── uncommend_and_upload.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Pycharm related: 2 | .idea/ 3 | .cache 4 | *__pycache__* 5 | 6 | # Hardware files not needed: 7 | *.s#* 8 | *.b#* 9 | 10 | # Virtual environment 11 | /venv/* 12 | 13 | # VS Code files 14 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MicroPythonScripts 2 | 3 | Main repository of MicroPython projects and modules I have built on my spare time. 4 | 5 | ## Structure of the repository 6 | 7 | - **`projects/`** 8 | 9 | Folder containing everything related to the script. 10 | 11 | | Name | Type | Description | 12 | | --------- | ------------- | ----------------------------------------------------------------------------------------------------------- | 13 | | `code` | :file_folder: | Commented code for better understanding of it. | 14 | | `release` | :file_folder: | Code without comments and trying to be as small as possible in order to save memory on the microcontroller. | 15 | | `docs` | :file_folder: | Files like images and so on for documentation purposes. | 16 | 17 | - **`modules`** 18 | 19 | Folder containing everything related to MicroPython and some help classes and scripts to make deployments more easy. 20 | 21 | | Name | Type | Description | 22 | | ---------- | ------------- | ----------------------------------------------------------------------------------------------------------- | 23 | | `code` | :file_folder: | Commented code for better understanding of it. | 24 | | `release` | :file_folder: | Code without comments and trying to be as small as possible in order to save memory on the microcontroller. | 25 | | `docs` | :file_folder: | Files like images and so on for documentation purposes. | 26 | | `examples` | :file_folder: | Example files that in some cases will need to be renamed into `main.py` so it will be run at boot time. | 27 | 28 | - **`snipets`** :file_folder: 29 | 30 | Scripts used to saved some common code so I don't forget how to do some things. 31 | 32 | - **`static`** :file_folder: 33 | 34 | Contains images for documentation purposes and other static files like HTML and CSS code. 35 | 36 | - **`tools`** :file_folder: 37 | 38 | Tools used when developing within this repo. 39 | 40 | - **`README.md`** :page_with_curl: on :file_folder: 41 | 42 | Documentation of the script, class or other important information. 43 | 44 | --- 45 | 46 | ## Project list 47 | 48 | | Project name | Status | Link | 49 | | :-------------- | :------- | ------------------------------------------- | 50 | | Bulleting board | **DONE** | [Get me there!](./projects/bulleting_board) | 51 | | Camera slider | **WIP** | [Get me there!](./projects/camera_slider) | 52 | | Micro server | **DONE** | [Get me there!](./projects/micro_server) | 53 | | Pomodoro | **DONE** | [Get me there!](./projects/pomodoro) | 54 | | Problem solver | **DONE** | [Get me there!](./projects/problem_solver) | 55 | | Script console | **DONE** | [Get me there!](./projects/script_console) | 56 | | Weather display | **DONE** | [Get me there!](./projects/weather_display) | 57 | | Weather station | **DONE** | [Get me there!](./projects/weather_station) | 58 | | WiFi scanner | **DONE** | [Get me there!](./projects/wifi_scan) | 59 | 60 | --- 61 | 62 | 63 | 64 | ## Support :mechanic: 65 | 66 | Reach out to me at one of the following places! 67 | 68 | - Website at [juanbiondi.com](https://www.juanbiondi.com) 69 | - Create an [issue](https://github.com/yeyeto2788/Things-Organizer/issues/new/choose) on this repository. :pirate_flag: 70 | - Send me an [email](mailto:jebp.freelance@gmail.com) :email: 71 | 72 | --- 73 | 74 | 75 | 76 | ## Contributing 77 | 78 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 79 | 80 | 1. Fork the Project 81 | 2. Create your Feature Branch (`git checkout -b feature/super_awesome_feature`) 82 | 3. Commit your Changes (`git commit -m 'Add some awesome feature'`) 83 | 4. Push to the Branch (`git push origin feature/super_awesome_feature`) 84 | 5. Open a Pull Request 85 | -------------------------------------------------------------------------------- /modules/uln2003/README.md: -------------------------------------------------------------------------------- 1 | # uln2003 class 2 | 3 | This class is made for using Stepper motor 28BYJ-48 4 | 5 | Stepper motor specs: 6 | * Step Angle = 5.625° / 64 7 | * Number of phase = 4 8 | * Speed Variation Ratio = 1/64 9 | 10 | From this data we can conclude that the **Steps per revolution** is equal to `(360 / (5.625° / 64)) / (FULL_STEP or HALF_STEP)`, there is also [this blog](http://www.jangeox.be/2013/10/stepper-motor-28byj-48_25.html) that states that these motors are not that accurate so it will be needed to change the Steps per revolution for in between `508` and `509` that is why in the code the FULL_ROTATION is set to `int(4075.7728395061727 / 8)`. 11 | 12 | The blog says the following: 13 | >I tried to speed things up to 500pps (2ms delay between steps), but then the motor also failed the test. The maximum speed without any load was 800 pps (1.2 ms delay or 5.0 seconds for one revolution). At higher pulses, the motor just stopped. 14 | 15 | Also keep in mind that a delay of less than 5 microseconds may cause the motor to simply buzz and not move at all. 16 | 17 | 18 | **Usage:** 19 | 20 | To use the module in a easy way we can do something like: 21 | 22 | ```python 23 | import uln2003 24 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=50) 25 | s1.step(100) # Rotate 100 steps clockwise 26 | s1.step(100, -1) # Rotate 100 steps anti-clockwise 27 | s1.step(uln2003.FULL_ROTATION) # Rotate 360 degrees clockwise 28 | s1.step(uln2003.FULL_ROTATION, -1) # Rotate 360 degrees anti-clockwise 29 | ``` 30 | 31 | The code above will be using `HALF_STEP` variable to do a half-stepping that it will take **8** steps to rotate the motor (Not taking into account the gears on the motor) if we want to do full-stepping we have to use the `FULL_STEP` variable that it will take **4** steps to rotate the motor (Also not taking into account the gears on the motor. 32 | 33 | We can instantiate more that one motor on the same script, to do so we can do something like: 34 | 35 | ```python 36 | import uln2003 37 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=5000) 38 | s2 = uln2003.Stepper(uln2003.HALF_STEP, 6, 5, 4, 3, delay=5000) 39 | s1.step(uln2003.FULL_ROTATION)# Rotate 360 degrees clockwise 40 | s2.step(uln2003.FULL_ROTATION)# Rotate 360 degrees clockwise 41 | ``` 42 | 43 | This code will make a full rotation of the motor (Taking into account the gears on it), first the motor 1 (`s1`) and then (`s2`). 44 | 45 | If we want to move two motor at the "same" time we can do the following: 46 | 47 | ```python 48 | import uln2003 49 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=5000) 50 | s2 = uln2003.Stepper(uln2003.HALF_STEP, 6, 5, 4, 3, delay=5000) 51 | c1 = uln2003.Command(s1, uln2003.FULL_ROTATION) # Go all the way round 52 | c2 = uln2003.Command(s2, uln2003.FULL_ROTATION/2, -1) # Go halfway round, backwards 53 | runner = uln2003.Driver() 54 | runner.run([c1, c2]) 55 | ``` 56 | --- 57 | ## Useful Variables: 58 | 59 | Within the module we have some useful variable that will help us to track the motor position or even the steps per revolution used on the motor. 60 | 61 | * **Stepper.delay**: Delay between steps (Recommend 10000+ for `FULL_STEP`, 1000 is OK for `HALF_STEP`) 62 | * **Stepper.steps_per_rev**: By default it set to `FULL_ROTATION` which has a value of (`int(4075.7728395061727 / 8)` about 509) 63 | * **Stepper.current_position**: It will give you the current count of steps done by the motor. 64 | 65 | --- 66 | ## Functions: 67 | 68 | * ### **Stepper.step(step_count, direction)** 69 | Rotates the Stepper motor a given number of steps. 70 | 71 | It also sets the current position of the stepper. 72 | 73 | The direction is set to 1 by default (clockwise) 74 | 75 | ##### **Arguments** 76 | * **`step_count`**: Integer with the number of steps to do. 77 | * **`direction`**: Integer (1 or -1) for forward and backward direction. 78 | 79 | * ### **Stepper.rel_angle(angle)** 80 | Rotate stepper for given relative angle. 81 | 82 | ##### **Arguments** 83 | * **`angle`**: Integer with the angle degrees. 84 | 85 | * ### **Stepper.abs_angle(angle)** 86 | Rotate stepper for given absolute angle since last power on. 87 | 88 | ##### **Arguments** 89 | * **`angle`**: Integer with the angle degrees. 90 | 91 | * ### **Stepper.revolution(rev_count)** 92 | Perform given number of full revolutions (360 degrees taking into account the motor gears) 93 | 94 | ##### **Arguments** 95 | * **`rev_count`**: Integer with the number of revolution to do. 96 | 97 | * ### **Stepper.set_step_delay(us)** 98 | Set time in microseconds between each step. 99 | 100 | Take into account that 20 us is the shortest possible for esp8266 101 | 102 | ##### **Arguments** 103 | * **`us`**: Integer with the number of microseconds. 104 | 105 | * ### **Stepper.set_steps_per_revolution()** 106 | Calculate and set the number of steps needed for one revolution. 107 | 108 | 109 | * ### **Stepper.reset()** 110 | Power off the motors and reset the steps count to zero. 111 | 112 | --- 113 | -------------------------------------------------------------------------------- /modules/uln2003/code/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 | Tell a stepper to move X many steps in a given direction 30 | """ 31 | def __init__(self, stepper, steps, direction=1): 32 | self.stepper = stepper 33 | self.steps = steps 34 | self.direction = direction 35 | 36 | 37 | class Driver: 38 | """ 39 | Drive a set of motors, each with their own commands 40 | """ 41 | 42 | @staticmethod 43 | def run(commands): 44 | """ 45 | Takes commands and calls the step function from the Stepper class in other to seem they are moving at the same time. 46 | 47 | Args: 48 | commands: List with the commands to execute. 49 | 50 | Returns: 51 | Nothing. 52 | """ 53 | 54 | # Work out total steps to take 55 | max_steps = sum([c.steps for c in commands]) 56 | 57 | count = 0 58 | while count != max_steps: 59 | for command in commands: 60 | # we want to interleave the commands 61 | if command.steps > 0: 62 | command.stepper.step(1, command.direction) 63 | command.steps -= 1 64 | count += 1 65 | 66 | 67 | class Stepper: 68 | def __init__(self, mode, pin1, pin2, pin3, pin4, delay=2000): 69 | self.mode = mode 70 | self.pin1 = machine.Pin(pin1, machine.Pin.OUT) 71 | self.pin2 = machine.Pin(pin2, machine.Pin.OUT) 72 | self.pin3 = machine.Pin(pin3, machine.Pin.OUT) 73 | self.pin4 = machine.Pin(pin4, machine.Pin.OUT) 74 | self.delay = delay # Recommend 10000+ for FULL_STEP, 1000 is OK for HALF_STEP 75 | self.steps_per_rev = FULL_ROTATION 76 | self.current_position = 0 77 | self.reset() # Initialize all to 0 78 | 79 | def step(self, step_count, direction=1): 80 | """ 81 | Rotates the Stepper motor a given number of steps. It also sets the current position of the stepper. 82 | 83 | Args: 84 | step_count: integer with the number of steps to do. 85 | direction: integer (1 or -1) for forward and backward direction. 86 | 87 | Returns: 88 | Nothing. 89 | """ 90 | for x in range(step_count): 91 | for bit in self.mode[::direction]: 92 | self.pin1.value(bit[0]) 93 | self.pin2.value(bit[1]) 94 | self.pin3.value(bit[2]) 95 | self.pin4.value(bit[3]) 96 | time.sleep_us(self.delay) 97 | self.current_position += (direction * step_count) 98 | 99 | def rel_angle(self, angle): 100 | """ 101 | Rotate stepper for given relative angle. 102 | 103 | Args: 104 | angle: Integer with the angle. 105 | 106 | Returns: 107 | Nothing. 108 | """ 109 | steps = int(angle / 360 * self.steps_per_rev) 110 | self.step(steps) 111 | 112 | def abs_angle(self, angle): 113 | """ 114 | Rotate stepper for given absolute angle since last power on. 115 | 116 | Args: 117 | angle: Integer with the angle. 118 | 119 | Returns: 120 | Nothing. 121 | """ 122 | steps = int(angle / 360 * self.steps_per_rev) 123 | steps -= self.current_position % self.steps_per_rev 124 | self.step(steps) 125 | 126 | def revolution(self, rev_count): 127 | """ 128 | Perform given number of full revolutions. 129 | 130 | Args: 131 | rev_count: Integer with the number of revolution to do. 132 | 133 | Returns: 134 | Nothing. 135 | """ 136 | self.step(rev_count * self.steps_per_rev) 137 | 138 | def set_step_delay(self, us): 139 | """ 140 | Set time in microseconds between each step. 141 | 142 | Args: 143 | us: integer with the number of microseconds. 144 | 145 | Returns: 146 | Nothing. 147 | """ 148 | if us < 20: # 20 us is the shortest possible for esp8266 149 | self.delay = 20 150 | else: 151 | self.delay = us 152 | 153 | def set_steps_per_revolution(self): 154 | """ 155 | Calculate the number of steps needed for one revolution. 156 | 157 | Returns: 158 | Nothing. 159 | """ 160 | self.steps_per_rev = int((360 / (5.625 / 64)) / len(self.mode)) 161 | 162 | def reset(self): 163 | """ 164 | Power off the motors and reset the steps count to zero. 165 | 166 | Returns: 167 | Nothing. 168 | """ 169 | self.pin1.value(0) 170 | self.pin2.value(0) 171 | self.pin3.value(0) 172 | self.pin4.value(0) 173 | if self.current_position > 0: 174 | self.current_position = 0 175 | -------------------------------------------------------------------------------- /modules/uln2003/docs/images/28BYJ-48-Pinout-Wirings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/modules/uln2003/docs/images/28BYJ-48-Pinout-Wirings.png -------------------------------------------------------------------------------- /modules/uln2003/docs/images/28BYJ-48-Stepper-Motor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/modules/uln2003/docs/images/28BYJ-48-Stepper-Motor.jpg -------------------------------------------------------------------------------- /modules/uln2003/docs/images/wemos_d1_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/modules/uln2003/docs/images/wemos_d1_mini.png -------------------------------------------------------------------------------- /modules/uln2003/docs/images/wemos_pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/modules/uln2003/docs/images/wemos_pinout.jpg -------------------------------------------------------------------------------- /modules/uln2003/examples/StepperTest.py: -------------------------------------------------------------------------------- 1 | import uln2003, time 2 | 3 | 4 | def hundred_steps(): 5 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=5000) 6 | print("Motor will move 100 steps clockwise") 7 | s1.step(100) # Rotate 100 steps clockwise 8 | print("Motor will move 100 steps counter-clockwise") 9 | s1.step(100, -1) # Rotate 100 steps anti-clockwise 10 | 11 | 12 | def one_by_one(): 13 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=5000) 14 | s2 = uln2003.Stepper(uln2003.HALF_STEP, 6, 5, 4, 3, delay=5000) 15 | print("Motor 1 will do a full rotation") 16 | s1.step(uln2003.FULL_ROTATION) 17 | print("Motor 2 will do a full rotation") 18 | s2.step(uln2003.FULL_ROTATION) 19 | 20 | 21 | def both_simultaneously(): 22 | s1 = uln2003.Stepper(uln2003.HALF_STEP, 16, 15, 14, 13, delay=5000) 23 | s2 = uln2003.Stepper(uln2003.HALF_STEP, 6, 5, 4, 3, delay=5000) 24 | 25 | print("Creating command 1") 26 | c1 = uln2003.Command(s1, uln2003.FULL_ROTATION) # Go all the way round 27 | print("Creating command 2") 28 | c2 = uln2003.Command(s2, uln2003.FULL_ROTATION/2, -1) # Go halfway round, backwards 29 | 30 | print("Initialize the driver class") 31 | runner = uln2003.Driver() 32 | print("Let's put both motors to run at the 'same' time") 33 | runner.run([c1, c2]) 34 | 35 | 36 | print("Starting hundred_steps() function.") 37 | hundred_steps() 38 | print("Funtion hundred_steps() finished!") 39 | time.sleep(2) 40 | print("Starting one_by_one() function. It will move 2 motors one by one") 41 | one_by_one() 42 | print("Funtion one_by_one() stopped.") 43 | time.sleep(2) 44 | print("Starting both_simultaneously() function. It will move both motors at the 'same' time") 45 | both_simultaneously() 46 | print("Funtion both_simultaneously() stopped.") 47 | time.sleep(2) 48 | print("Script finished!. SEE YA!") 49 | -------------------------------------------------------------------------------- /modules/uln2003/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 | -------------------------------------------------------------------------------- /modules/witty_utils/README.md: -------------------------------------------------------------------------------- 1 | # WittyUtils class 2 | -------------------------------------------------------------------------------- /modules/witty_utils/code/witty_utils.py: -------------------------------------------------------------------------------- 1 | import machine 2 | 3 | 4 | class WittyBoard: 5 | IN = 0 6 | OUT = 1 7 | PWM = 2 8 | pins = {"leds": { 9 | "green_led": { 10 | "pin": 12, 11 | "mode": OUT 12 | }, 13 | "red_led": { 14 | "pin": 15, 15 | "mode": OUT 16 | }, 17 | "blue_led": { 18 | "pin": 13, 19 | "mode": OUT 20 | }, 21 | "builtin_led": { 22 | "pin": 2, 23 | "mode": OUT 24 | } 25 | }, 26 | "button": { 27 | "pin": 4, 28 | "mode": IN 29 | } 30 | } 31 | 32 | @classmethod 33 | def clear_leds(cls): 34 | """ 35 | Turns off the leds on the board. 36 | 37 | Returns: 38 | Nothing. 39 | """ 40 | for pin in cls.pins['leds']: 41 | if pin != 'builtin_led': 42 | if cls.pins['leds'][pin]['mode'] == cls.PWM: 43 | machine.PWM(machine.Pin(cls.pins['leds'][pin]['pin'])).deinit() 44 | cls.pins['leds'][pin]['mode'] = cls.OUT 45 | machine.Pin(cls.pins['leds'][pin]['pin'], machine.Pin.OUT).off() 46 | 47 | @classmethod 48 | def read_button(cls): 49 | """ 50 | Reads the actual value of the button on the board 51 | 52 | Returns: 53 | Button input value. 54 | """ 55 | return machine.Pin(cls.pins['button']['pin'], machine.Pin.IN).value() 56 | 57 | @staticmethod 58 | def read_adc(): 59 | """ 60 | Reads the value from the Analog to Digital converter. 61 | 62 | Returns: 63 | The actual value of the ADC. 64 | """ 65 | return machine.ADC(0).read() 66 | 67 | @classmethod 68 | def set_boolean_value(cls, strled, blnstatus): 69 | """ 70 | Turns off and on the given led. 71 | 72 | Args: 73 | strled: String with the name of the led 74 | blnstatus: Boolean to which you want to set the led to. 75 | 76 | Returns: 77 | Nothing. 78 | """ 79 | if strled in cls.pins['leds']: 80 | if cls.pins['leds'][strled]['mode'] == cls.PWM: 81 | machine.PWM(machine.Pin(cls.pins['leds'][strled]['pin'])).deinit() 82 | cls.pins['leds'][strled]['mode'] = cls.OUT 83 | machine.Pin(cls.pins['leds'][strled]['pin'], machine.Pin.OUT).value(blnstatus) 84 | 85 | @classmethod 86 | def set_pwm_value(cls, strled, intduty): 87 | """ 88 | Will set a PWM pin for setting brightness off the led. There are some parameter to take into 89 | account which are written below. 90 | duty: 0 - 1023 (pin being high) 91 | freq: 1Hz - 1Khz 92 | Args: 93 | strled: String with the name of the led 94 | intduty: Integer for the duty on the PWM 95 | 96 | Returns: 97 | Nothing. 98 | """ 99 | if strled in cls.pins['leds']: 100 | machine.PWM(machine.Pin(cls.pins['leds'][strled]['pin']), freq=500).duty(intduty) 101 | cls.pins['leds'][strled]['mode'] = cls.PWM 102 | -------------------------------------------------------------------------------- /modules/witty_utils/examples/pomodoro.py: -------------------------------------------------------------------------------- 1 | from witty_utils import WittyBoard 2 | import time 3 | 4 | witty = WittyBoard() 5 | 6 | 7 | def toggle_led(intmins, strled): 8 | """ 9 | Toggles an LED for a given amount of minutes. 10 | 11 | Args: 12 | intmins: Integer with the minutes to toggle the led. 13 | strled: String with the name of the led. 14 | 15 | Returns: 16 | Nothing. 17 | """ 18 | initvalue = 0 19 | initial_time = time.ticks_ms() 20 | itertime = initial_time 21 | witty.clear_leds() 22 | while ((time.ticks_ms() - initial_time) / 1000) < (intmins * 60): 23 | if (time.ticks_ms() - itertime) >= 1000: 24 | initvalue = not initvalue 25 | witty.set_boolean_value(strled, initvalue) 26 | itertime = time.ticks_ms() 27 | witty.clear_leds() 28 | 29 | 30 | witty.clear_leds() 31 | while True: 32 | if not witty.read_button(): 33 | witty.set_boolean_value('blue_led', 0) 34 | toggle_led(25, "red_led") 35 | toggle_led(5, "green_led") 36 | else: 37 | witty.set_boolean_value('blue_led', 1) 38 | -------------------------------------------------------------------------------- /modules/witty_utils/release/witty_utils.py: -------------------------------------------------------------------------------- 1 | import machine 2 | 3 | class WittyBoard: 4 | IN = 0 5 | OUT = 1 6 | PWM = 2 7 | pins = {"leds": { 8 | "green_led": { 9 | "pin": 12, 10 | "mode": OUT 11 | }, 12 | "red_led": { 13 | "pin": 15, 14 | "mode": OUT 15 | }, 16 | "blue_led": { 17 | "pin": 13, 18 | "mode": OUT 19 | }, 20 | "builtin_led": { 21 | "pin": 2, 22 | "mode": OUT 23 | } 24 | }, 25 | "button": { 26 | "pin": 4, 27 | "mode": IN 28 | } 29 | } 30 | 31 | @classmethod 32 | def clear_leds(cls): 33 | for pin in cls.pins['leds']: 34 | if pin != 'builtin_led': 35 | if cls.pins['leds'][pin]['mode'] == cls.PWM: 36 | machine.PWM(machine.Pin(cls.pins['leds'][pin]['pin'])).deinit() 37 | cls.pins['leds'][pin]['mode'] = cls.OUT 38 | machine.Pin(cls.pins['leds'][pin]['pin'], machine.Pin.OUT).off() 39 | 40 | @classmethod 41 | def read_button(cls): 42 | return machine.Pin(cls.pins['button']['pin'], machine.Pin.IN).value() 43 | 44 | @staticmethod 45 | def read_adc(): 46 | return machine.ADC(0).read() 47 | 48 | @classmethod 49 | def set_boolean_value(cls, strled, blnstatus): 50 | if strled in cls.pins['leds']: 51 | if cls.pins['leds'][strled]['mode'] == cls.PWM: 52 | machine.PWM(machine.Pin(cls.pins['leds'][strled]['pin'])).deinit() 53 | cls.pins['leds'][strled]['mode'] = cls.OUT 54 | machine.Pin(cls.pins['leds'][strled]['pin'], machine.Pin.OUT).value(blnstatus) 55 | 56 | @classmethod 57 | def set_pwm_value(cls, strled, intduty): 58 | if strled in cls.pins['leds']: 59 | machine.PWM(machine.Pin(cls.pins['leds'][strled]['pin']), freq=500).duty(intduty) 60 | cls.pins['leds'][strled]['mode'] = cls.PWM 61 | -------------------------------------------------------------------------------- /projects/bulleting_board/README.md: -------------------------------------------------------------------------------- 1 | # MicroBoard 2 | 3 | The idea of this script is to host a bulleting board on a webserver based on the ESP8266 where it will read the messages stored on a file called `messages.txt` from within the ESP8266 . This will create an access point to where you can connect and read the messages and post messages on it. 4 | 5 | What we need to do is download all the code from the `release` folder and rename the `MicroBoard.py` file to `main.py` so it will be executed after booting up. 6 | 7 | ### Image of code running on the witty cloud board: 8 | 9 |

10 | Drawing 11 |

12 | 13 | ## Parts needed: 14 | 15 | - ESP8266 16 | 17 | I'm using the Witty Cloud (ESP8266 based) board 18 | 19 |

20 | 21 |

22 | 23 | ## TO DO: 24 | 25 | - [ ] Add real execution image / video. 26 | 30 | 31 | - [ ] Better documentation. 32 | -------------------------------------------------------------------------------- /projects/bulleting_board/release/bulleting_board.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import gc 4 | 5 | file_name = "messages.txt" 6 | 7 | def check_file(): 8 | if file_name in os.listdir(): 9 | return True 10 | else: 11 | with open(file_name, "w") as f: 12 | f.close() 13 | return True 14 | 15 | def clear_file(): 16 | with open(file_name, "w") as f: 17 | f.write("") 18 | f.close() 19 | 20 | def get_file_size(): 21 | with open(file_name, "r") as f: 22 | lines = f.readlines() 23 | f.close() 24 | return len(lines) 25 | 26 | def quick_decode(s_decode): 27 | elements = {"ñ": "%C3%B1", "€": "%E2,%AC", ";": "%3B", "?": "%3F", "/": "%2F", ":": "%3A", "#": "%23", "&": "%26", 28 | "=": "%3D", "+": "%2B", "$": "%24", ",": "%2C", "%": "%25", "<": "%3C", ">": "%3E", "@": "%40", 29 | "(": "%28", ")": "%29", "‚": "%82", "!": "%21"} 30 | if "+" in s_decode: 31 | s_decode = s_decode.replace("+", " ") 32 | if "%20" in s_decode: 33 | s_decode = s_decode.replace("%20", " ") 34 | for element in elements: 35 | if elements[element] in s_decode: 36 | s_decode = s_decode.replace(elements[element], element) 37 | return s_decode 38 | 39 | def write_file(message): 40 | if (message != "#") or (len(message) > 2): 41 | message = quick_decode(message) 42 | total_messages = read_file() 43 | if get_file_size() > 15: 44 | del total_messages[0] 45 | total_messages.append(message) 46 | with open(file_name, "w") as f: 47 | for item in total_messages: 48 | f.write(item + "\n") 49 | f.close() 50 | 51 | def read_file(): 52 | filedata = [] 53 | if check_file() is True: 54 | with open(file_name, "r") as messages: 55 | data = messages.readlines() 56 | if len(data) > 0: 57 | for line in data: 58 | message = line.rstrip() 59 | filedata.append(message) 60 | else: 61 | filedata.append("NO MESSAGES") 62 | return filedata 63 | 64 | def linted_data(): 65 | data = [] 66 | for element in read_file(): 67 | data.append("\n%s\n" % element) 68 | return data 69 | 70 | def main(): 71 | check_file() 72 | html = """ 73 | 74 | 75 | Message board 76 | 77 | 78 | 92 | 93 | 94 |
95 |
96 |

Message board

97 |

98 |
99 | %s

Messages

100 |
101 |

Type a message:


102 |
103 |
104 |




105 |
106 |
107 |
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 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
SensorValueTimestamp
Temperature1010:00
Temperature1111:00
Luminosity1111:00
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 |

16 | Wemos d1 mini board 17 |

18 | 19 | - OLED display (I2C) 20 | 21 |

22 | Wemos D1 Oled Display 23 |

24 | 25 | - Buzzer 26 | 27 | - LEDs or Neopixel strip. 28 | 29 |

30 | 12 neopixel ring pcb 31 |

32 | 33 | ## Custom PCB for the project. 34 | 35 |

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
VersionTop side of the boardPlacement of componentsComments
Version 0.1Top side of boardPlacement of componentsUse this version if you do not wish to use the OLED LCD display.
Version 0.2Top side of boardPlacement of componentsThis version comes with 4 push buttons and 2 I2C connectors. You can see schematics here.
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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
ItemQuantity
WS2812B Neopixel12
100 pf Capacitor (SMD 1206)12
SMD 1k Resistor (SMD 1206)4
6mm Push button4
Plain PCB (around 6x6 cm)1
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 | Wemos d1 mini board 24 |

25 | 26 | - **OLED display (I2C)** 27 | 28 |

29 | Wemos D1 Oled Display 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 | Wemos d1 mini board 33 |

34 | 35 | - **OLED display (I2C)** 36 | 37 |

38 | Wemos D1 Oled Display 39 |

40 | 41 | - **Push buttons** 42 | 43 |

44 | Push button image 45 | Push button image 46 | Push button image 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 | MicroScriptConsole logo on display 69 | Micropython logo on display 70 |

71 | Python logo on display 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 | Print test script running on display 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 |
  • - [ ] Bitcoin price tracker.
  • 143 |
  • - [ ] NeoPixels example.
  • 144 |
  • - [ ] DHT mqtt publisher.
  • 145 |
  • - [x] WiFi Scanner.
  • 146 |
  • - [ ] Analog Input reader.
  • 147 |
  • - [ ] PWM and/or Servo controller.
  • 148 |
  • - [ ] Stepper controlled [uln2003](https://github.com/yeyeto2788/MicroPythonScripts/tree/master/HelpScripts/Modules/uln2003).
149 | 150 | - [ ] **Tools to be added:** 151 |
  • - [ ] Board Code uploader.
  • 152 |
  • - [ ] Zip folder creation tool for all code within `Releases`.
153 | 154 | ## Special thanks to: 155 | 156 | - [Radomir Dopieralski](https://github.com/deshipu) for the reply on the [MicroPython Forum](https://forum.micropython.org/viewtopic.php?f=16&t=5119) 157 | - [Mike Causer](https://github.com/mcauser) for letting me port the Conway's Game of Life [script](https://github.com/mcauser/MicroPython-ESP8266-Nokia-5110-Conways-Game-of-Life) 158 | -------------------------------------------------------------------------------- /projects/script_console/code/menu.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import sys 4 | import console 5 | 6 | 7 | keys = console.Keypad() 8 | oled = console.Display() 9 | 10 | 11 | def print_menu(words): 12 | """ 13 | Function to print the menu when the script initializes. 14 | 15 | Args: 16 | words: List with words to be printed. 17 | 18 | Returns: 19 | None. 20 | """ 21 | if isinstance(words, list) and len(words) <= 8: 22 | line = 0 23 | for script in words: 24 | if line > len(oled.v_lines): 25 | time.sleep(2) 26 | line = 0 27 | oled.print_on_line(str(script), line) 28 | line += 1 29 | else: 30 | oled.print_wrapped(words) 31 | time.sleep(1) 32 | 33 | 34 | def print_selection(scripts, selection): 35 | """ 36 | Print current selected script on the screen. 37 | 38 | Args: 39 | scripts: List with the script on the filesystem. 40 | selection: Integer with the selection of the script. 41 | 42 | Returns: 43 | None. 44 | """ 45 | oled.clear(0, 1) 46 | oled.print_on_line("Script selected:" + str(selection), 1) 47 | oled.print_on_line(str(scripts[selection]), 2) 48 | oled.draw_rect(0, oled.v_lines[2], oled.width, oled.char_width) 49 | oled.draw_rect_filled(oled.width - oled.char_width, oled.v_lines[2], oled.char_width, oled.char_width) 50 | 51 | 52 | def get_files(): 53 | """ 54 | Gets the files from the filesystem except for the ones on the 'excluded_files' 55 | variable. 56 | 57 | Returns: 58 | None. 59 | """ 60 | extensions = ".py" 61 | excluded_files = ["main.py", "boot.py", "console.py", __name__] 62 | dirfiles = [] 63 | for filename in os.listdir(os.getcwd()): 64 | if filename.lower().endswith(extensions): 65 | if filename.lower() not in excluded_files: 66 | dirfiles.append(filename.replace(extensions, "")) 67 | return dirfiles 68 | 69 | 70 | scripts = get_files() 71 | selection = 0 72 | while True: 73 | start_time = time.ticks_ms() // 1000 74 | console_idle = 0 75 | oled.clear(0, 1) 76 | print_menu(scripts[0:len(oled.v_lines)]) 77 | while True: 78 | time_now = time.ticks_ms() // 1000 79 | buttons = keys.get_keypad() 80 | btnUp = buttons[0] 81 | btnDown = buttons[1] 82 | btnSelect = buttons[2] 83 | btnStart = buttons[3] 84 | if buttons and btnDown == 0: 85 | try: 86 | start_time = time.ticks_ms() // 1000 87 | selection += 1 88 | if selection > (len(scripts) - 1): 89 | selection = 0 90 | print_selection(scripts, selection) 91 | console_idle = 0 92 | except: 93 | pass 94 | elif buttons and btnUp == 0: 95 | try: 96 | start_time = time.ticks_ms() // 1000 97 | selection -= 1 98 | if selection < 0: 99 | selection = len(scripts) - 1 100 | print_selection(scripts, selection) 101 | console_idle = 0 102 | except: 103 | pass 104 | elif buttons and btnStart == 0: 105 | start_time = time.ticks_ms() // 1000 106 | try: 107 | __import__(scripts[selection]) 108 | except console.ConsoleError: 109 | oled.clear(0, 1) 110 | oled.print_wrapped("Going back to main menu.") 111 | time.sleep(0.5) 112 | continue 113 | del sys.modules[scripts[selection]] 114 | 115 | if (time_now - start_time) > (3 * 60): 116 | if not console_idle: 117 | oled.clear(0, 1) 118 | oled.print_on_line(" TIME IS OUT!!! ", 1) 119 | oled.print_on_line("Shutting off the", 5) 120 | oled.print_on_line(" screen ", 6) 121 | time.sleep(2) 122 | oled.clear(0, 1) 123 | console_idle = 1 124 | elif (time_now - start_time) > 5: 125 | if not console_idle: 126 | start_time = time.ticks_ms() // 1000 127 | selection += 1 128 | if selection > (len(scripts) - 1): 129 | selection = 0 130 | print_selection(scripts, selection) 131 | time.sleep(0.1) 132 | del scripts 133 | time.sleep(0.1) 134 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/I2C_scanner.py: -------------------------------------------------------------------------------- 1 | import time 2 | from console import Display 3 | 4 | oled = Display() 5 | 6 | 7 | oled.print_wrapped("Scanning I2C Devices on the bus...") 8 | time.sleep(0.5) 9 | devices = oled.i2c.scan() 10 | 11 | if len(devices) == 0: 12 | oled.clear(0, 1) 13 | oled.print_wrapped("No I2C devices found :(") 14 | 15 | else: 16 | oled.clear(0, 1) 17 | oled.print_wrapped('%s I2C devices found' % str(len(devices))) 18 | time.sleep(1.5) 19 | 20 | for count in range(1, 2): 21 | for device in devices: 22 | oled.clear(0, 1) 23 | oled.print_on_line("Decimal address:", 2) 24 | oled.print_on_line(str(device), 3) 25 | oled.print_on_line("Hex address:", 4) 26 | oled.print_on_line(str(hex(device)), 5) 27 | time.sleep(1) 28 | oled.clear(0, 1) 29 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/conways_game_of_life.py: -------------------------------------------------------------------------------- 1 | from time import sleep_ms 2 | from console import Button 3 | from console import Display 4 | from urandom import getrandbits 5 | 6 | """ 7 | This code was ported from the https://github.com/mcauser/MicroPython-ESP8266-Nokia-5110-Conways-Game-of-Life 8 | so most of the credit goes to Mike Causer 9 | """ 10 | 11 | 12 | class ConwaysGameOfLife: 13 | def __init__(self): 14 | self.best = 0 15 | self.oled = Display() 16 | self.width = self.oled.width 17 | self.height = self.oled.height 18 | self.select_button = Button(0) 19 | 20 | def center_text(self, txt): 21 | """ 22 | This function will center all incomming strings to a fix size of the display 23 | max_char property. 24 | 25 | Args: 26 | txt: String to be centered. 27 | 28 | Returns: 29 | type: String with the text centered 30 | """ 31 | return '{: ^{}}'.format(txt, self.oled.max_char) 32 | 33 | def intro(self): 34 | """ 35 | It will print the intro on the oled display with a sleep of 1 second so 36 | the message will be visible. 37 | 38 | Returns: 39 | Nothing. 40 | """ 41 | self.oled.display.fill(0) 42 | self.oled.print_on_line(self.center_text("Conway's"), 2) 43 | self.oled.print_on_line(self.center_text("Game"), 3) 44 | self.oled.print_on_line(self.center_text("of"), 4) 45 | self.oled.print_on_line(self.center_text("Life"), 5) 46 | sleep_ms(1000) 47 | 48 | def end(self, generations, best, size): 49 | """ 50 | It will ouput on the oled display the Generations, best score and the 51 | size of the pixels. 52 | 53 | Args: 54 | generations: Integer with the generations created. 55 | best: Integer the best score. 56 | size: Integer with the size of the pixels. 57 | 58 | Returns: 59 | Nothing. 60 | """ 61 | self.oled.clear(0, 1) 62 | self.oled.print_on_line(self.center_text("Generations"), 0) 63 | self.oled.print_on_line(self.center_text(str(generations)), 1) 64 | self.oled.print_on_line(self.center_text("Best Score"), 3) 65 | self.oled.print_on_line(self.center_text(str(best)), 4) 66 | self.oled.print_on_line(self.center_text("Pixel Size"), 5) 67 | self.oled.print_on_line(self.center_text(str(size)), 6) 68 | sleep_ms(2000) 69 | self.oled.clear(0, 1) 70 | 71 | def begin(self, size=4, delay=20): 72 | """ 73 | Main function to check the button to stop the game or if game has ended. 74 | If so, then call the `end` function to show the results. 75 | 76 | Args: 77 | size: Integer with the size of the pixels. 78 | delay: Integer of the delay between generations (In milliseconds). 79 | 80 | Returns: 81 | Nothing. 82 | """ 83 | self.size = size # Size of lifeforms in pixels 84 | self.delay = delay # Delay in ms between generations 85 | 86 | # Localised to avoid self lookups 87 | # Possible performance optimisation, TBC 88 | delay = self.delay 89 | tick = self.tick 90 | self.randomise() # Randomise initial pixels 91 | 92 | generations = 0 # Begin 93 | try: 94 | while (tick() and self.select_button.is_released()): 95 | generations = generations + 1 96 | self.oled.display.show() 97 | sleep_ms(delay) 98 | except KeyboardInterrupt: 99 | pass 100 | 101 | if generations > self.best: # New high score? 102 | self.best = generations 103 | 104 | self.end(generations, self.best, self.size) # End 105 | 106 | def randomise(self): 107 | """ 108 | Generate a seudo-random cells on the screen. 109 | 110 | Returns: 111 | Nothing. 112 | """ 113 | size = self.size 114 | width = self.width 115 | height = self.height 116 | self.oled.display.fill(0) 117 | 118 | for x in range(0, width, size): 119 | for y in range(0, height, size): 120 | # random bit: 0 = pixel off, 1 = pixel on 121 | self.cell(x, y, getrandbits(1)) 122 | 123 | def cell(self, x, y, colour): 124 | """ 125 | This will assign a value to a given pixel. 126 | 127 | Args: 128 | x: Integer with the `x` axis position. 129 | y: Integer with the `y` axis position. 130 | colour: Boolean with the value to be assigned. 131 | 132 | Returns: 133 | Nothing. 134 | """ 135 | size = self.size 136 | for i in range(size): 137 | for j in range(size): 138 | self.oled.display.pixel(x + i, y + j, colour) 139 | 140 | def get(self, x, y): 141 | """ 142 | Function to return the value of the given pixel x, y. 143 | 144 | Args: 145 | x: Integer with the `x` axis position. 146 | y: Integer with the `y` axis position. 147 | 148 | Returns: 149 | type: Boolean with the value of the pixel. 150 | """ 151 | if not 0 <= x < self.width or not 0 <= y < self.height: 152 | return 0 153 | if self.oled.display.pixel(x, y) is None: 154 | bln_return = getrandbits(1) 155 | else: 156 | bln_return = self.oled.display.pixel(x, y) 157 | return bln_return & 1 158 | 159 | def tick(self): 160 | """ 161 | This function will apply the game rules getting the live cells and the ones 162 | that have to die. 163 | 164 | Returns: 165 | Boolean to keep the game going or not. 166 | """ 167 | size = self.size 168 | width = self.width 169 | height = self.height 170 | get = self.get 171 | cell = self.cell 172 | 173 | # If no pixels are born or die, the game ends 174 | something_happened = False 175 | 176 | for x in range(0, width, size): 177 | for y in range(0, height, size): 178 | 179 | alive = get(x, y) # Is the current cell alive 180 | 181 | # Count number of neighbours 182 | neighbours = ( 183 | get(x - size, y - size) + 184 | get(x, y - size) + 185 | get(x + size, y - size) + 186 | get(x - size, y) + 187 | get(x + size, y) + 188 | get(x + size, y + size) + 189 | get(x, y + size) + 190 | get(x - size, y + size) 191 | ) 192 | 193 | # Apply the game rules 194 | if alive and not 2 <= neighbours <= 3: 195 | cell(x, y, 0) # This pixel dies 196 | if not something_happened: 197 | something_happened = True 198 | elif not alive and neighbours == 3: 199 | cell(x, y, 1) # A new pixel is born 200 | if not something_happened: 201 | something_happened = True 202 | return something_happened 203 | 204 | 205 | a = ConwaysGameOfLife() 206 | a.intro() 207 | a.begin(4, 10) 208 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/img/MSC_logo.txt: -------------------------------------------------------------------------------- 1 | 00100000000004000000000000C000 2 | C1F800003C000E018F00000000C000 3 | E1C000006600000198C0000000C000 4 | E3D1C79C6338F4FBD8C7171C38CE00 5 | F2D326366064C4D9900D99366CD900 6 | F6D236633C46C48D9018D130C6D180 7 | D6D206630E40C48D9018D11EC6FF80 8 | DCD20663C340C48D98D8D106C6D000 9 | DCD336366666C4D998CD91226CD900 10 | CCD1C61C3C38C4B9CF07111C38CF80 11 | 000000000000008000000000000000 12 | 000000000000008000000000000000 13 | 000000000000008000000000000000 14 | 000000000000000000000000000000 15 | 000000000000000000000000000000 16 | 000000003FFFDFFFE0000000000000 17 | 000000003FFFDFFFE0000000000000 18 | 000000003FFFDFFFE0000000000000 19 | 000000003FFFDFFFE0000000000000 20 | 000000003FFFDFFFE0000000000000 21 | 000000003FFFDFFFE0000000000000 22 | 000000003FFFDFFFE0000000000000 23 | 000000003FFFDFFFE0000000000000 24 | 000000003F9FDFCFE0000000000000 25 | 000000003F9FDFCFE0000000000000 26 | 000000003F9FDFCFE0000000000000 27 | 000000003F9FDFCFE0000000000000 28 | 000000003F9FDFCFE0000000000000 29 | 000000003F9FDFCFE0000000000000 30 | 000000003F9FDFCFE0000000000000 31 | 000000003F9FDFCFE0000000000000 32 | 000000003F9FDFCFE0000000000000 33 | 000000003F9FDFCFE0000000000000 34 | 000000003F9FDFCFE0000000000000 35 | 000000003F9FDFCFE0000000000000 36 | 000000003F9FDFCFE0000000000000 37 | 000000003F9FDFCFE0000000000000 38 | 000000003F9FDFCFE0000000000000 39 | 000000003F9FDFCFE0000000000000 40 | 000000003F9FDFCFE0000000000000 41 | 000000003F9FDFCFE0000000000000 42 | 000000003F9FFFCFE0000000000000 43 | 000000003F9FFFCCE0000000000000 44 | 000000003F9FFFCCE0000000000000 45 | 000000003F9FFFCEE0000000000000 46 | 000000003F9FFFCFE0000000000000 47 | 000000003F9FFFCFE0000000000000 48 | 000000003F9FFFCFE0000000000000 49 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/img/github_logo.txt: -------------------------------------------------------------------------------- 1 | 000003FFFC000000 2 | 00001FFFFF800000 3 | 00007FFFFFE00000 4 | 0001FFFFFFF80000 5 | 0003FFFFFFFC0000 6 | 000FFFFFFFFF0000 7 | 001FFFFFFFFF8000 8 | 003FFFFFFFFFC000 9 | 007FFFFFFFFFE000 10 | 00FFFFFFFFFFF000 11 | 01FFFFFFFFFFF800 12 | 03F8FFFFFFF1FC00 13 | 07F81FFFFF81FE00 14 | 07F80FFFFF01FE00 15 | 0FF002000400FF00 16 | 1FF000000000FF80 17 | 1FF000000000FF80 18 | 3FF000000000FFC0 19 | 3FF000000000FFC0 20 | 7FF800000001FFE0 21 | 7FF800000001FFE0 22 | 7FF000000000FFE0 23 | FFE0000000007FF0 24 | FFE0000000007FF0 25 | FFC0000000003FF0 26 | FFC0000000003FF0 27 | FFC0000000003FF0 28 | FFC0000000003FF0 29 | FF80000000001FF0 30 | FF80000000001FF0 31 | FFC0000000003FF0 32 | FFC0000000003FF0 33 | FFC0000000003FF0 34 | FFC0000000003FF0 35 | FFC0000000003FF0 36 | FFE0000000007FF0 37 | FFE0000000007FF0 38 | FFF000000000FFF0 39 | FFF000000000FFF0 40 | 7FF800000001FFE0 41 | 7FFC00000003FFE0 42 | 7FFE00000007FFE0 43 | 3E1F8000001FFFC0 44 | 3C0FE000007FFFC0 45 | 1F07FE0007FFFF80 46 | 0F83FC0003FFFF00 47 | 0FC1FC0003FFFF00 48 | 07C0FC0003FFFE00 49 | 03E0000003FFFC00 50 | 03E0000003FFF800 51 | 01F0000003FFF800 52 | 00F8000003FFF000 53 | 007C000003FFE000 54 | 003E000003FFC000 55 | 000FFC0003FF8000 56 | 0007FC0003FE0000 57 | 0003FC0003FC0000 58 | 0001FC0003F80000 59 | 00003C0003C00000 60 | 0000080001000000 61 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/img/python_logo.txt: -------------------------------------------------------------------------------- 1 | 0000300000 2 | 000FFFC000 3 | 001BFFE000 4 | 0030FFE000 5 | 0030FFF000 6 | 0030FFF000 7 | 003BFFF000 8 | 003FFFF000 9 | 00000FF000 10 | 00000FF000 11 | 0FFFFFF3E0 12 | 1FFFFFF3F0 13 | 3FFFFFF3F0 14 | 7FFFFFF3F8 15 | 7FFFFFF3F8 16 | 7FFFFFE7F8 17 | 7FFFFFE7F8 18 | 7FFFFFCFF8 19 | FFF0001FF8 20 | 7FC0007FFC 21 | 7F8FFFFFF8 22 | 7F9FFFFFF8 23 | 7F3FFFFFF8 24 | 7F3FFFFFF8 25 | 7F3FFFFFF8 26 | 3F3FFFFFF0 27 | 3F3FFFFFF0 28 | 0F3FFFFFC0 29 | 003FC00000 30 | 003FC00000 31 | 003FFFF000 32 | 003FFE7000 33 | 003FFC3000 34 | 003FFC3000 35 | 001FFC2000 36 | 000FFFC000 37 | 0007FF8000 38 | 0000200000 39 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/img/upython_logo.txt: -------------------------------------------------------------------------------- 1 | FFFFFFFE1FFFFFFFC0 2 | FFFFFFFE1FFFFFFFC0 3 | FFFFFFFE1FFFFFFFC0 4 | FFFFFFFE1FFFFFFFC0 5 | FFFFFFFE1FFFFFFFC0 6 | FFFFFFFE1FFFFFFFC0 7 | FFFFFFFE1FFFFFFFC0 8 | FFFFFFFE1FFFFFFFC0 9 | FFFFFFFE1FFFFFFFC0 10 | FFFFFFFE1FFFFFFFC0 11 | FFFFFFFE1FFFFFFFC0 12 | FFFFFFFE1FFFFFFFC0 13 | FFFFFFFE1FFFFFFFC0 14 | FFFFFFFE1FFFFFFFC0 15 | FFFC7FFE1FFF8FFFC0 16 | FFFC3FFE1FFF0FFFC0 17 | FFFC3FFE1FFF0FFFC0 18 | FFFC3FFE1FFF0FFFC0 19 | FFFC3FFE1FFF0FFFC0 20 | FFFC3FFE1FFF0FFFC0 21 | FFFC3FFE1FFF0FFFC0 22 | FFFC3FFE1FFF0FFFC0 23 | FFFC3FFE1FFF0FFFC0 24 | FFFC3FFE1FFF0FFFC0 25 | FFFC3FFE1FFF0FFFC0 26 | FFFC3FFE1FFF0FFFC0 27 | FFFC3FFE1FFF0FFFC0 28 | FFFC3FFE1FFF0FFFC0 29 | FFFC3FFE1FFF0FFFC0 30 | FFFC3FFE1FFF0FFFC0 31 | FFFC3FFE1FFF0FFFC0 32 | FFFC3FFE1FFF0FFFC0 33 | FFFC3FFE1FFF0FFFC0 34 | FFFC3FFE1FFF0FFFC0 35 | FFFC3FFE1FFF0FFFC0 36 | FFFC3FFE1FFF0FFFC0 37 | FFFC3FFE1FFF0FFFC0 38 | FFFC3FFE1FFF0FFFC0 39 | FFFC3FFE1FFF0FFFC0 40 | FFFC3FFE1FFF0FFFC0 41 | FFFC3FFE1FFF0FFFC0 42 | FFFC3FFE1FFF0FFFC0 43 | FFFC3FFE1FFF0FFFC0 44 | FFFC3FFE1FFF0FFFC0 45 | FFFC3FFE1FFF0FFFC0 46 | FFFC3FFE1FFF0FFFC0 47 | FFFC3FFE1FFF0FFFC0 48 | FFFC3FFE1FFF0FFFC0 49 | FFFC3FFE1FFF0FFFC0 50 | FFFC3FFE1FFF0FFFC0 51 | FFFC3FFE1FFF0FFFC0 52 | FFFC3FFE1FFF0FFFC0 53 | FFFC3FFFFFFF0FFFC0 54 | FFFC3FFFFFFF0FC3C0 55 | FFFC3FFFFFFF0F83C0 56 | FFFC3FFFFFFF0F83C0 57 | FFFC3FFFFFFF0F83C0 58 | FFFC3FFFFFFF0F83C0 59 | FFFC3FFFFFFF0F83C0 60 | FFFC3FFFFFFF0F83C0 61 | FFFC3FFFFFFF0FC7C0 62 | FFFC3FFFFFFF0FFFC0 63 | FFFC3FFFFFFF0FFFC0 64 | FFFC3FFFFFFF0FFFC0 65 | FFFC3FFFFFFF0FFFC0 66 | FFFC3FFFFFFF0FFFC0 67 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/img/upython_logo_s.txt: -------------------------------------------------------------------------------- 1 | FFFE3FFF80 2 | FFFE3FFF80 3 | FFFE3FFF80 4 | FFFE3FFF80 5 | FFFE3FFF80 6 | FFFE3FFF80 7 | FFFE3FFF80 8 | FE7E3F3F80 9 | FE7E3F3F80 10 | FE7E3F3F80 11 | FE7E3F3F80 12 | FE7E3F3F80 13 | FE7E3F3F80 14 | FE7E3F3F80 15 | FE7E3F3F80 16 | FE7E3F3F80 17 | FE7E3F3F80 18 | FE7E3F3F80 19 | FE7E3F3F80 20 | FE7E3F3F80 21 | FE7E3F3F80 22 | FE7E3F3F80 23 | FE7E3F3F80 24 | FE7E3F3F80 25 | FE7F7F3F80 26 | FE7F7F3F80 27 | FE7FFF3B80 28 | FE7FFF3180 29 | FE7FFF3180 30 | FE7FFF3180 31 | FE7FFF3B80 32 | FE7FFF3F80 33 | FE7FFF3F80 34 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/magic8_ball.py: -------------------------------------------------------------------------------- 1 | import time 2 | import urandom 3 | from console import Display, Button 4 | 5 | oled = Display() 6 | buttonSelect = Button(0) 7 | 8 | answers = [ 9 | "It is certain", 10 | "It is decidedly so", 11 | "Without a doubt", 12 | "Yes, definitely", 13 | "You may rely on it", 14 | "As I see it, yes", 15 | "Most likely", 16 | "Outlook good", 17 | "Yes", 18 | "Signs point to yes", 19 | "Reply hazy try again", 20 | "Ask again later", 21 | "Better not tell you now", 22 | "Cannot predict now", 23 | "Concentrate and ask again", 24 | "Don't count on it" 25 | "My reply is no", 26 | "My sources say no", 27 | "Outlook not so good", 28 | "Very doubtful"] 29 | 30 | 31 | def get_random_str(items): 32 | """ 33 | Select a seudo-random string from a given list. 34 | 35 | Args: 36 | items (lst): List from where to select item. 37 | 38 | Returns: 39 | item selected value. 40 | """ 41 | choise = urandom.getrandbits(5) 42 | try: 43 | s_return = items[choise] 44 | return s_return 45 | except IndexError: 46 | return get_random_str(items) 47 | 48 | 49 | def main(): 50 | oled.print_wrapped(" Magic 8 Ball ") 51 | time.sleep(1) 52 | 53 | while True: 54 | if not buttonSelect.is_released(): 55 | oled.clear(0, 1) 56 | time.sleep(1) 57 | oled.print_wrapped(get_random_str(answers)) 58 | 59 | 60 | main() -------------------------------------------------------------------------------- /projects/script_console/code/scripts/rubber_duck_debugging.py: -------------------------------------------------------------------------------- 1 | import time 2 | import urandom 3 | from console import Display, Button 4 | 5 | oled = Display() 6 | buttonSelect = Button(0) 7 | 8 | questions = ["Which person around you could help you?", 9 | "Maybe you should consider refactoring?", 10 | "Have you tried step by step execution?", 11 | "Maybe some threads are unnecessary?", 12 | "Maybe you turn it off and on again?", 13 | "Could there be some race condition?", 14 | "Where is the lacking print()?", 15 | "Have you talked to your colleague?", 16 | "Why not call for a group meeting?", 17 | "Why not walk around your office?", 18 | "Should you really be doing this?", 19 | "Can the problem be broken down?", 20 | "Have you tried to unit test it?", 21 | "Maybe it is time for a coffee?", 22 | "Have you tried a clean build?", 23 | "Can you give me more details?", 24 | "Can this be hardware related?", 25 | "Could this not be your fault?", 26 | "Is this actually a problem?", 27 | "Can the code be simplified?", 28 | "Have you tried googling it?", 29 | "Maybe you can turn it on and off?", 30 | "I am not sure try again!", 31 | "Try again after having a coffee!", 32 | "Walk around the office and try again!", 33 | "Have you tried pair programming this?", 34 | "Maybe some of the threads are unnecessary?", 35 | "Can the problem be broken down more?", 36 | "Call for a group meeting to discuss this!", 37 | "Maybe you should consider some refactoring!", 38 | "Have you tried googling it?", 39 | "Why not try it again?"] 40 | 41 | 42 | def get_random_str(items): 43 | """ 44 | Select a seudo-random string from a given list. 45 | 46 | Args: 47 | items (lst): List from where to select item. 48 | 49 | Returns: 50 | item selected value. 51 | """ 52 | choise = urandom.getrandbits(5) 53 | try: 54 | s_return = items[choise] 55 | return s_return 56 | except IndexError: 57 | return get_random_str(items) 58 | 59 | 60 | def main(): 61 | oled.clear(1, 1) 62 | time.sleep(0.2) 63 | oled.clear(0, 1) 64 | 65 | while True: 66 | if not buttonSelect.is_released(): 67 | oled.clear(0, 1) 68 | time.sleep(1) 69 | oled.print_wrapped(get_random_str(questions)) 70 | 71 | main() -------------------------------------------------------------------------------- /projects/script_console/code/scripts/show_images.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | from console import Display 4 | 5 | 6 | def show(): 7 | """ 8 | Cycle through the images showing them. 9 | 10 | Returns: 11 | None 12 | """ 13 | oled = Display() 14 | 15 | available_img = [image for image in os.listdir() if image.endswith('.txt')] 16 | for image in available_img: 17 | oled.clear(0, 1) 18 | oled.draw_graphic(image, 35, 2) 19 | time.sleep(5) 20 | 21 | 22 | show() 23 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/simple_test.py: -------------------------------------------------------------------------------- 1 | import console, time 2 | 3 | keys = console.Keypad() 4 | display = console.Display() 5 | 6 | 7 | def center_text(txt): 8 | """ 9 | This function will center all incoming strings to a fix size of the display 10 | max_char property. 11 | 12 | Args: 13 | txt: String to be centered. 14 | 15 | Returns: 16 | type: String with the text centered 17 | """ 18 | return '{: ^{}}'.format(txt, display.max_char) 19 | 20 | 21 | display.print_on_line(center_text("Wujuuu imported"), 0) 22 | display.print_on_line(center_text("Press the"), 3) 23 | display.print_on_line(center_text("button 0 to"), 4) 24 | display.print_on_line(center_text("count presses"), 5) 25 | 26 | intCounter = 0 27 | 28 | while True: 29 | buttons = keys.get_keypad() 30 | if buttons and buttons[3] == 0: 31 | intCounter += 1 32 | display.clear(0, 1) 33 | display.print_on_line(center_text("IT IS WORKING!!!"), 0) 34 | display.print_on_line(center_text("Button presses"), 3) 35 | display.print_on_line(center_text(str(intCounter)), 5) 36 | time.sleep_ms(250) 37 | if intCounter > 10: 38 | break 39 | -------------------------------------------------------------------------------- /projects/script_console/code/scripts/wifi_scanner.py: -------------------------------------------------------------------------------- 1 | import time 2 | import network 3 | 4 | import gc 5 | gc.enable() 6 | 7 | from console import Display 8 | 9 | 10 | class WiFiScanner: 11 | def __init__(self): 12 | self.name = '' 13 | self.strength = '' 14 | self.status = '' 15 | self.kanaal = '' 16 | self.oled = Display() 17 | self.wlan = network.WLAN(network.STA_IF) 18 | self.prepare_wifi() 19 | time.sleep_ms(5000) 20 | self.oled.print_wrapped("Performing scan...") 21 | time.sleep(0.5) 22 | self.oled.clear(0, 1) 23 | self.format() 24 | 25 | def prepare_wifi(self): 26 | """ 27 | Function to disable WiFi if it is in an active connection. 28 | 29 | Returns: 30 | Nothing. 31 | """ 32 | if not self.wlan.active(): 33 | self.oled.print_wrapped("Turning the WiFi ON.") 34 | time.sleep(0.5) 35 | self.oled.clear(0, 1) 36 | self.wlan.active(True) 37 | elif self.wlan.active() and self.wlan.isconnected(): 38 | self.oled.print_wrapped("Disconnecting from WiFi connection.") 39 | time.sleep(0.5) 40 | self.oled.clear(0, 1) 41 | self.wlan.disconnect() 42 | 43 | def format(self): 44 | """ 45 | Format information looping from the wlan.scan performed. 46 | 47 | Returns: 48 | Nothing. 49 | """ 50 | try: 51 | wlan_list = self.wlan.scan() 52 | except: 53 | wlan_list = [['NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE']] 54 | for counter in wlan_list: 55 | self.name = str(counter[0], 'utf8') 56 | self.strength = str(counter[3]) + ' dBm' 57 | self.kanaal = 'Channel: ' + str(counter[2]) 58 | self.status = self.get_secure(counter[4]) 59 | self.show_info() 60 | self.oled.clear(0, 1) 61 | 62 | @staticmethod 63 | def get_secure(num): 64 | """ 65 | Convert the number from wlan.scan into something human readable. 66 | 67 | Args: 68 | num: Integer from the scan regarding authmode. 69 | 70 | Returns: 71 | String with the conversion of the authmode. 72 | """ 73 | s_return = "" 74 | try: 75 | if int(num) == 0: 76 | s_return = 'Open wifi' 77 | elif int(num) == 1: 78 | s_return = 'WEP' 79 | elif int(num) ==2: 80 | s_return = 'WPA-PSK' 81 | elif int(num) == 3: 82 | s_return = 'WPA2-PSK' 83 | elif int(num) == 4: 84 | s_return = 'WPA/WPA2-PSK' 85 | else: 86 | s_return = str("UNKNOWN %s" % num) 87 | 88 | return s_return 89 | except: 90 | return s_return 91 | 92 | def show_info(self): 93 | """ 94 | Show information on the Display nicely. 95 | 96 | Returns: 97 | Nothing. 98 | """ 99 | self.oled.clear(0, 1) 100 | if len(self.name) > 15: 101 | self.oled.print_on_line(self.name[0:15], 0) 102 | self.oled.print_on_line(self.name[15:int(len(self.name))], 1) 103 | else: 104 | self.oled.print_on_line(self.name, 0) 105 | 106 | self.oled.print_on_line(self.strength, 2, 30) 107 | self.oled.print_on_line(self.status, 3, 30) 108 | self.oled.print_on_line(self.kanaal, 4, 30) 109 | self.oled.print_on_line((str(gc.mem_free()) + " B"), 5, 30) 110 | time.sleep_ms(10000) 111 | 112 | ScannedWiFi = WiFiScanner() 113 | -------------------------------------------------------------------------------- /projects/script_console/firmware/script_console_0001.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/firmware/script_console_0001.bin -------------------------------------------------------------------------------- /projects/script_console/hardware/01/KeyPad.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/KeyPad.fzz -------------------------------------------------------------------------------- /projects/script_console/hardware/01/KeyPad_bom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Fritzing Bill of Materials 6 | 28 | 29 | 30 | 31 |

Bill of Materials: KeyPad.fzz

32 |

D:/Files/Python/GitHub/MicroPythonScripts/MicroScriptConsole/PCB/v0.1/KeyPad.fzz

33 |

jueves, septiembre 13 2018, 11:25:56

34 | 35 |

Assembly List

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
LabelPart TypeProperties
JP1M16package 1x16_machine-pin-header_lock.004; variant machiine-pin_lock
JP2Header 4package 1x04-smd; variant smd
S1Pushbuttonpackage [THT]
S2Pushbuttonpackage [THT]
S3Pushbuttonpackage [THT]
69 |

Shopping List

70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
AmountPart TypeProperties
1M16package 1x16_machine-pin-header_lock.004; variant machiine-pin_lock
1Header 4package 1x04-smd; variant smd
3Pushbuttonpackage [THT]
94 |


Exported with Fritzing 0.9.3- http://fritzing.org

95 | 96 | 97 | -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_contour.gm1: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 SINGLE SIDED* 4 | G04 HOLES NOT PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10R,1.653540X0.590551*% 12 | %ADD11C,0.008000*% 13 | %ADD10C,0.008*% 14 | %LNCONTOUR*% 15 | G90* 16 | G70* 17 | G54D10* 18 | G54D11* 19 | X4Y587D02* 20 | X1650Y587D01* 21 | X1650Y4D01* 22 | X4Y4D01* 23 | X4Y587D01* 24 | D02* 25 | G04 End of contour* 26 | M02* -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_copperBottom.gbl: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 SINGLE SIDED* 4 | G04 HOLES NOT PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.075000*% 12 | %ADD11C,0.055000*% 13 | %ADD12R,0.039370X0.118110*% 14 | %ADD13C,0.024000*% 15 | %LNCOPPER0*% 16 | G90* 17 | G70* 18 | G54D10* 19 | X748Y437D03* 20 | X748Y182D03* 21 | X571Y437D03* 22 | X571Y182D03* 23 | X1071Y443D03* 24 | X1071Y187D03* 25 | X894Y443D03* 26 | X894Y187D03* 27 | X1371Y443D03* 28 | X1371Y187D03* 29 | X1194Y443D03* 30 | X1194Y187D03* 31 | G54D11* 32 | X71Y87D03* 33 | X171Y79D03* 34 | X271Y87D03* 35 | X371Y79D03* 36 | X471Y87D03* 37 | X571Y79D03* 38 | X671Y87D03* 39 | X771Y79D03* 40 | X871Y87D03* 41 | X971Y79D03* 42 | X1071Y87D03* 43 | X1171Y79D03* 44 | X1271Y87D03* 45 | X1371Y79D03* 46 | X1471Y87D03* 47 | X1571Y79D03* 48 | G54D12* 49 | X471Y237D03* 50 | X371Y237D03* 51 | X271Y237D03* 52 | X171Y237D03* 53 | G54D13* 54 | X597Y170D02* 55 | X671Y138D01* 56 | D02* 57 | X671Y138D02* 58 | X671Y116D01* 59 | D02* 60 | X821Y113D02* 61 | X795Y95D01* 62 | D02* 63 | X821Y137D02* 64 | X821Y113D01* 65 | D02* 66 | X870Y171D02* 67 | X821Y137D01* 68 | D02* 69 | X1400Y82D02* 70 | X1443Y85D01* 71 | D02* 72 | X1371Y159D02* 73 | X1371Y108D01* 74 | D02* 75 | X821Y537D02* 76 | X765Y461D01* 77 | D02* 78 | X1058Y469D02* 79 | X1021Y537D01* 80 | D02* 81 | X1021Y537D02* 82 | X821Y537D01* 83 | D02* 84 | X1021Y537D02* 85 | X1321Y537D01* 86 | D02* 87 | X1321Y537D02* 88 | X1358Y469D01* 89 | D02* 90 | X996Y237D02* 91 | X996Y162D01* 92 | D02* 93 | X996Y162D02* 94 | X896Y102D01* 95 | D02* 96 | X1121Y263D02* 97 | X1021Y263D01* 98 | D02* 99 | X1021Y263D02* 100 | X996Y237D01* 101 | D02* 102 | X1174Y208D02* 103 | X1121Y263D01* 104 | D02* 105 | X272Y537D02* 106 | X672Y537D01* 107 | D02* 108 | X672Y537D02* 109 | X731Y460D01* 110 | D02* 111 | X171Y437D02* 112 | X272Y537D01* 113 | D02* 114 | X171Y291D02* 115 | X171Y437D01* 116 | D02* 117 | X1571Y212D02* 118 | X1571Y108D01* 119 | D02* 120 | X1421Y337D02* 121 | X1571Y212D01* 122 | D02* 123 | X571Y337D02* 124 | X1421Y337D01* 125 | D02* 126 | X485Y252D02* 127 | X571Y337D01* 128 | D02* 129 | X271Y237D02* 130 | X271Y116D01* 131 | D02* 132 | X271Y237D02* 133 | X271Y237D01* 134 | D02* 135 | X371Y237D02* 136 | X371Y108D01* 137 | D02* 138 | X371Y237D02* 139 | X371Y237D01* 140 | G04 End of Copper0* 141 | M02* -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_drill.txt: -------------------------------------------------------------------------------- 1 | ; NON-PLATED HOLES START AT T1 2 | ; THROUGH (PLATED) HOLES START AT T100 3 | M48 4 | INCH 5 | T1C0.055118 6 | T100C0.035000 7 | % 8 | T1 9 | X004211Y004342 10 | X002211Y004342 11 | T100 12 | X011711Y000794 13 | X011940Y004433 14 | X005711Y004374 15 | X008940Y001874 16 | X010712Y004433 17 | X007483Y004374 18 | X009711Y000794 19 | X013712Y004433 20 | X000711Y000874 21 | X014711Y000874 22 | X011940Y001874 23 | X005711Y001815 24 | X004711Y000874 25 | X015711Y000794 26 | X013712Y001874 27 | X010711Y000874 28 | X010712Y001874 29 | X005711Y000794 30 | X013711Y000794 31 | X008940Y004433 32 | X007483Y001815 33 | X012711Y000874 34 | X008711Y000874 35 | X002711Y000874 36 | X003711Y000794 37 | X007711Y000794 38 | X006711Y000874 39 | X001711Y000794 40 | T00 41 | M30 42 | -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_maskBottom.gbs: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 SINGLE SIDED* 4 | G04 HOLES NOT PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.085000*% 12 | %ADD11C,0.065000*% 13 | %ADD12C,0.065118*% 14 | %ADD13R,0.049370X0.128110*% 15 | %LNMASK0*% 16 | G90* 17 | G70* 18 | G54D10* 19 | X748Y437D03* 20 | X748Y182D03* 21 | X571Y437D03* 22 | X571Y182D03* 23 | X1071Y443D03* 24 | X1071Y187D03* 25 | X894Y443D03* 26 | X894Y187D03* 27 | X1371Y443D03* 28 | X1371Y187D03* 29 | X1194Y443D03* 30 | X1194Y187D03* 31 | G54D11* 32 | X71Y87D03* 33 | X171Y79D03* 34 | X271Y87D03* 35 | X371Y79D03* 36 | X471Y87D03* 37 | X571Y79D03* 38 | X671Y87D03* 39 | X771Y79D03* 40 | X871Y87D03* 41 | X971Y79D03* 42 | X1071Y87D03* 43 | X1171Y79D03* 44 | X1271Y87D03* 45 | X1371Y79D03* 46 | X1471Y87D03* 47 | X1571Y79D03* 48 | G54D12* 49 | X221Y434D03* 50 | X421Y434D03* 51 | X221Y434D03* 52 | X421Y434D03* 53 | X221Y434D03* 54 | X421Y434D03* 55 | G54D13* 56 | X471Y237D03* 57 | X371Y237D03* 58 | X271Y237D03* 59 | X171Y237D03* 60 | G04 End of Mask0* 61 | M02* -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_pasteMaskBottom.gbp: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 SINGLE SIDED* 4 | G04 HOLES NOT PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.055118*% 12 | %ADD11R,0.039370X0.118110*% 13 | %LNPASTEMASK0*% 14 | G90* 15 | G70* 16 | G54D10* 17 | X221Y434D03* 18 | X421Y434D03* 19 | X221Y434D03* 20 | X421Y434D03* 21 | X221Y434D03* 22 | X421Y434D03* 23 | G54D11* 24 | X471Y237D03* 25 | X371Y237D03* 26 | X271Y237D03* 27 | X171Y237D03* 28 | G04 End of PasteMask0* 29 | M02* -------------------------------------------------------------------------------- /projects/script_console/hardware/01/gerber/KeyPad_pnp.txt: -------------------------------------------------------------------------------- 1 | *Pick And Place List 2 | *Company= 3 | *Author= 4 | *eMail= 5 | * 6 | *Project=KeyPad 7 | *Date=11:21:59 8 | *CreatedBy=Fritzing 0.9.3b.04.19.5c895d327c44a3114e5fcc9d8260daf0cbb52806 9 | * 10 | * 11 | *Coordinates in mm, always center of component 12 | *Origin 0/0=Lower left corner of PCB 13 | *Rotation in degree (0-360, math. pos.) 14 | * 15 | *No;Value;Package;X;Y;Rotation;Side;Name 16 | 1;;[THT];24.9583;-8.01072;-90;Bottom;S2 17 | 2;;1x16_machine-pin-header_lock.004;20.8583;-2.11907;0;Bottom;JP1 18 | 3;;[THT];32.5783;-8.01072;-90;Bottom;S3 19 | 4;;1x04-smd;8.15825;-11.4374;180;Bottom;JP2 20 | 5;;[THT];16.7582;-7.86061;-90;Bottom;S1 21 | -------------------------------------------------------------------------------- /projects/script_console/hardware/01/images/KeyPad_pcb.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/images/KeyPad_pcb.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/images/KeyPad_pcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/images/KeyPad_pcb.png -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_copper_bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_copper_bottom.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_copper_bottom_mirror.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_copper_bottom_mirror.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_mask_bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_mask_bottom.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_mask_bottom_mirror.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_mask_bottom_mirror.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_paste_mask_bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_paste_mask_bottom.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_paste_mask_bottom_mirror.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_paste_mask_bottom_mirror.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_silk_bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_silk_bottom.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_silk_bottom_mirror.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_silk_bottom_mirror.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_silk_top.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_silk_top.pdf -------------------------------------------------------------------------------- /projects/script_console/hardware/01/pdf/KeyPad_etch_silk_top_mirror.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/hardware/01/pdf/KeyPad_etch_silk_top_mirror.pdf -------------------------------------------------------------------------------- /projects/script_console/other_tools/TheDotFactory-0.1.4.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/other_tools/TheDotFactory-0.1.4.7z -------------------------------------------------------------------------------- /projects/script_console/other_tools/images/bmp/micro_console.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/other_tools/images/bmp/micro_console.bmp -------------------------------------------------------------------------------- /projects/script_console/other_tools/images/bmp/python.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/other_tools/images/bmp/python.bmp -------------------------------------------------------------------------------- /projects/script_console/other_tools/images/bmp/upython_m.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/other_tools/images/bmp/upython_m.bmp -------------------------------------------------------------------------------- /projects/script_console/other_tools/images/bmp/upython_s.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/projects/script_console/other_tools/images/bmp/upython_s.bmp -------------------------------------------------------------------------------- /projects/script_console/release/menu.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import sys 4 | import console 5 | 6 | keys = console.Keypad() 7 | oled = console.Display() 8 | 9 | def print_menu(words): 10 | if isinstance(words, list) and len(words) <= 8: 11 | line = 0 12 | for script in words: 13 | if line > len(oled.v_lines): 14 | time.sleep(2) 15 | line = 0 16 | oled.print_on_line(str(script), line) 17 | line += 1 18 | else: 19 | oled.print_wrapped(words) 20 | time.sleep(1) 21 | 22 | def print_selection(scripts, selection): 23 | oled.clear(0, 1) 24 | oled.print_on_line("Script selected:" + str(selection), 1) 25 | oled.print_on_line(str(scripts[selection]), 2) 26 | oled.draw_rect(0, oled.v_lines[2], oled.width, oled.char_width) 27 | oled.draw_rect_filled(oled.width - oled.char_width, oled.v_lines[2], oled.char_width, oled.char_width) 28 | 29 | def get_files(): 30 | extensions = ".py" 31 | excluded_files = ["main.py", "boot.py", "console.py", __name__] 32 | dirfiles = [] 33 | for filename in os.listdir(os.getcwd()): 34 | if filename.lower().endswith(extensions): 35 | if filename.lower() not in excluded_files: 36 | dirfiles.append(filename.replace(extensions, "")) 37 | return dirfiles 38 | 39 | scripts = get_files() 40 | selection = 0 41 | while True: 42 | start_time = time.ticks_ms() // 1000 43 | console_idle = 0 44 | oled.clear(0, 1) 45 | print_menu(scripts[0:len(oled.v_lines)]) 46 | while True: 47 | time_now = time.ticks_ms() // 1000 48 | buttons = keys.get_keypad() 49 | btnUp = buttons[0] 50 | btnDown = buttons[1] 51 | btnSelect = buttons[2] 52 | btnStart = buttons[3] 53 | if buttons and btnDown == 0: 54 | try: 55 | start_time = time.ticks_ms() // 1000 56 | selection += 1 57 | if selection > (len(scripts) - 1): 58 | selection = 0 59 | print_selection(scripts, selection) 60 | console_idle = 0 61 | except: 62 | pass 63 | elif buttons and btnUp == 0: 64 | try: 65 | start_time = time.ticks_ms() // 1000 66 | selection -= 1 67 | if selection < 0: 68 | selection = len(scripts) - 1 69 | print_selection(scripts, selection) 70 | console_idle = 0 71 | except: 72 | pass 73 | elif buttons and btnStart == 0: 74 | start_time = time.ticks_ms() // 1000 75 | try: 76 | __import__(scripts[selection]) 77 | except console.ConsoleError: 78 | oled.clear(0, 1) 79 | oled.print_wrapped("Going back to main menu.") 80 | time.sleep(0.5) 81 | continue 82 | del sys.modules[scripts[selection]] 83 | 84 | if (time_now - start_time) > (3 * 60): 85 | if not console_idle: 86 | oled.clear(0, 1) 87 | oled.print_on_line(" TIME IS OUT!!! ", 1) 88 | oled.print_on_line("Shutting off the", 5) 89 | oled.print_on_line(" screen ", 6) 90 | time.sleep(2) 91 | oled.clear(0, 1) 92 | console_idle = 1 93 | elif (time_now - start_time) > 5: 94 | if not console_idle: 95 | start_time = time.ticks_ms() // 1000 96 | selection += 1 97 | if selection > (len(scripts) - 1): 98 | selection = 0 99 | print_selection(scripts, selection) 100 | time.sleep(0.1) 101 | del scripts 102 | time.sleep(0.1) 103 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/I2C_scanner.py: -------------------------------------------------------------------------------- 1 | import time 2 | from console import Display 3 | 4 | oled = Display() 5 | 6 | oled.print_wrapped("Scanning I2C Devices on the bus...") 7 | time.sleep(0.5) 8 | devices = oled.i2c.scan() 9 | 10 | if len(devices) == 0: 11 | oled.clear(0, 1) 12 | oled.print_wrapped("No I2C devices found :(") 13 | else: 14 | oled.clear(0, 1) 15 | oled.print_wrapped('%s I2C devices found' % str(len(devices))) 16 | time.sleep(1.5) 17 | 18 | for count in range(1, 2): 19 | for device in devices: 20 | oled.clear(0, 1) 21 | oled.print_on_line("Decimal address:", 2) 22 | oled.print_on_line(str(device), 3) 23 | oled.print_on_line("Hex address:", 4) 24 | oled.print_on_line(str(hex(device)), 5) 25 | time.sleep(1) 26 | oled.clear(0, 1) 27 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/conways_game_of_life.py: -------------------------------------------------------------------------------- 1 | from time import sleep_ms 2 | from console import Button 3 | from console import Display 4 | from urandom import getrandbits 5 | 6 | class ConwaysGameOfLife: 7 | def __init__(self): 8 | self.best = 0 9 | self.oled = Display() 10 | self.width = self.oled.width 11 | self.height = self.oled.height 12 | self.select_button = Button(0) 13 | 14 | def center_text(self, txt): 15 | return '{: ^{}}'.format(txt, self.oled.max_char) 16 | 17 | def intro(self): 18 | self.oled.display.fill(0) 19 | self.oled.print_on_line(self.center_text("Conway's"), 2) 20 | self.oled.print_on_line(self.center_text("Game"), 3) 21 | self.oled.print_on_line(self.center_text("of"), 4) 22 | self.oled.print_on_line(self.center_text("Life"), 5) 23 | sleep_ms(1000) 24 | 25 | def end(self, generations, best, size): 26 | self.oled.clear(0, 1) 27 | self.oled.print_on_line(self.center_text("Generations"), 0) 28 | self.oled.print_on_line(self.center_text(str(generations)), 1) 29 | self.oled.print_on_line(self.center_text("Best Score"), 3) 30 | self.oled.print_on_line(self.center_text(str(best)), 4) 31 | self.oled.print_on_line(self.center_text("Pixel Size"), 5) 32 | self.oled.print_on_line(self.center_text(str(size)), 6) 33 | sleep_ms(2000) 34 | self.oled.clear(0, 1) 35 | 36 | def begin(self, size=4, delay=20): 37 | self.size = size 38 | self.delay = delay 39 | delay = self.delay 40 | tick = self.tick 41 | self.randomise() 42 | generations = 0 43 | try: 44 | while (tick() and self.select_button.is_released()): 45 | generations = generations + 1 46 | self.oled.display.show() 47 | sleep_ms(delay) 48 | except KeyboardInterrupt: 49 | pass 50 | 51 | if generations > self.best: 52 | self.best = generations 53 | 54 | self.end(generations, self.best, self.size) 55 | 56 | def randomise(self): 57 | size = self.size 58 | width = self.width 59 | height = self.height 60 | self.oled.display.fill(0) 61 | 62 | for x in range(0, width, size): 63 | for y in range(0, height, size): 64 | self.cell(x, y, getrandbits(1)) 65 | 66 | def cell(self, x, y, colour): 67 | size = self.size 68 | for i in range(size): 69 | for j in range(size): 70 | self.oled.display.pixel(x + i, y + j, colour) 71 | 72 | def get(self, x, y): 73 | if not 0 <= x < self.width or not 0 <= y < self.height: 74 | return 0 75 | if self.oled.display.pixel(x, y) is None: 76 | bln_return = getrandbits(1) 77 | else: 78 | bln_return = self.oled.display.pixel(x, y) 79 | return bln_return & 1 80 | 81 | def tick(self): 82 | size = self.size 83 | width = self.width 84 | height = self.height 85 | get = self.get 86 | cell = self.cell 87 | something_happened = False 88 | 89 | for x in range(0, width, size): 90 | for y in range(0, height, size): 91 | alive = get(x, y) 92 | neighbours = ( 93 | get(x - size, y - size) + 94 | get(x, y - size) + 95 | get(x + size, y - size) + 96 | get(x - size, y) + 97 | get(x + size, y) + 98 | get(x + size, y + size) + 99 | get(x, y + size) + 100 | get(x - size, y + size) 101 | ) 102 | 103 | if alive and not 2 <= neighbours <= 3: 104 | cell(x, y, 0) 105 | if not something_happened: 106 | something_happened = True 107 | elif not alive and neighbours == 3: 108 | cell(x, y, 1) 109 | if not something_happened: 110 | something_happened = True 111 | return something_happened 112 | 113 | a = ConwaysGameOfLife() 114 | a.intro() 115 | a.begin(4, 10) 116 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/img/MSC_logo.txt: -------------------------------------------------------------------------------- 1 | 00100000000004000000000000C000 2 | C1F800003C000E018F00000000C000 3 | E1C000006600000198C0000000C000 4 | E3D1C79C6338F4FBD8C7171C38CE00 5 | F2D326366064C4D9900D99366CD900 6 | F6D236633C46C48D9018D130C6D180 7 | D6D206630E40C48D9018D11EC6FF80 8 | DCD20663C340C48D98D8D106C6D000 9 | DCD336366666C4D998CD91226CD900 10 | CCD1C61C3C38C4B9CF07111C38CF80 11 | 000000000000008000000000000000 12 | 000000000000008000000000000000 13 | 000000000000008000000000000000 14 | 000000000000000000000000000000 15 | 000000000000000000000000000000 16 | 000000003FFFDFFFE0000000000000 17 | 000000003FFFDFFFE0000000000000 18 | 000000003FFFDFFFE0000000000000 19 | 000000003FFFDFFFE0000000000000 20 | 000000003FFFDFFFE0000000000000 21 | 000000003FFFDFFFE0000000000000 22 | 000000003FFFDFFFE0000000000000 23 | 000000003FFFDFFFE0000000000000 24 | 000000003F9FDFCFE0000000000000 25 | 000000003F9FDFCFE0000000000000 26 | 000000003F9FDFCFE0000000000000 27 | 000000003F9FDFCFE0000000000000 28 | 000000003F9FDFCFE0000000000000 29 | 000000003F9FDFCFE0000000000000 30 | 000000003F9FDFCFE0000000000000 31 | 000000003F9FDFCFE0000000000000 32 | 000000003F9FDFCFE0000000000000 33 | 000000003F9FDFCFE0000000000000 34 | 000000003F9FDFCFE0000000000000 35 | 000000003F9FDFCFE0000000000000 36 | 000000003F9FDFCFE0000000000000 37 | 000000003F9FDFCFE0000000000000 38 | 000000003F9FDFCFE0000000000000 39 | 000000003F9FDFCFE0000000000000 40 | 000000003F9FDFCFE0000000000000 41 | 000000003F9FDFCFE0000000000000 42 | 000000003F9FFFCFE0000000000000 43 | 000000003F9FFFCCE0000000000000 44 | 000000003F9FFFCCE0000000000000 45 | 000000003F9FFFCEE0000000000000 46 | 000000003F9FFFCFE0000000000000 47 | 000000003F9FFFCFE0000000000000 48 | 000000003F9FFFCFE0000000000000 49 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/img/github_logo.txt: -------------------------------------------------------------------------------- 1 | 000003FFFC000000 2 | 00001FFFFF800000 3 | 00007FFFFFE00000 4 | 0001FFFFFFF80000 5 | 0003FFFFFFFC0000 6 | 000FFFFFFFFF0000 7 | 001FFFFFFFFF8000 8 | 003FFFFFFFFFC000 9 | 007FFFFFFFFFE000 10 | 00FFFFFFFFFFF000 11 | 01FFFFFFFFFFF800 12 | 03F8FFFFFFF1FC00 13 | 07F81FFFFF81FE00 14 | 07F80FFFFF01FE00 15 | 0FF002000400FF00 16 | 1FF000000000FF80 17 | 1FF000000000FF80 18 | 3FF000000000FFC0 19 | 3FF000000000FFC0 20 | 7FF800000001FFE0 21 | 7FF800000001FFE0 22 | 7FF000000000FFE0 23 | FFE0000000007FF0 24 | FFE0000000007FF0 25 | FFC0000000003FF0 26 | FFC0000000003FF0 27 | FFC0000000003FF0 28 | FFC0000000003FF0 29 | FF80000000001FF0 30 | FF80000000001FF0 31 | FFC0000000003FF0 32 | FFC0000000003FF0 33 | FFC0000000003FF0 34 | FFC0000000003FF0 35 | FFC0000000003FF0 36 | FFE0000000007FF0 37 | FFE0000000007FF0 38 | FFF000000000FFF0 39 | FFF000000000FFF0 40 | 7FF800000001FFE0 41 | 7FFC00000003FFE0 42 | 7FFE00000007FFE0 43 | 3E1F8000001FFFC0 44 | 3C0FE000007FFFC0 45 | 1F07FE0007FFFF80 46 | 0F83FC0003FFFF00 47 | 0FC1FC0003FFFF00 48 | 07C0FC0003FFFE00 49 | 03E0000003FFFC00 50 | 03E0000003FFF800 51 | 01F0000003FFF800 52 | 00F8000003FFF000 53 | 007C000003FFE000 54 | 003E000003FFC000 55 | 000FFC0003FF8000 56 | 0007FC0003FE0000 57 | 0003FC0003FC0000 58 | 0001FC0003F80000 59 | 00003C0003C00000 60 | 0000080001000000 61 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/img/python_logo.txt: -------------------------------------------------------------------------------- 1 | 0000300000 2 | 000FFFC000 3 | 001BFFE000 4 | 0030FFE000 5 | 0030FFF000 6 | 0030FFF000 7 | 003BFFF000 8 | 003FFFF000 9 | 00000FF000 10 | 00000FF000 11 | 0FFFFFF3E0 12 | 1FFFFFF3F0 13 | 3FFFFFF3F0 14 | 7FFFFFF3F8 15 | 7FFFFFF3F8 16 | 7FFFFFE7F8 17 | 7FFFFFE7F8 18 | 7FFFFFCFF8 19 | FFF0001FF8 20 | 7FC0007FFC 21 | 7F8FFFFFF8 22 | 7F9FFFFFF8 23 | 7F3FFFFFF8 24 | 7F3FFFFFF8 25 | 7F3FFFFFF8 26 | 3F3FFFFFF0 27 | 3F3FFFFFF0 28 | 0F3FFFFFC0 29 | 003FC00000 30 | 003FC00000 31 | 003FFFF000 32 | 003FFE7000 33 | 003FFC3000 34 | 003FFC3000 35 | 001FFC2000 36 | 000FFFC000 37 | 0007FF8000 38 | 0000200000 39 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/img/upython_logo.txt: -------------------------------------------------------------------------------- 1 | FFFFFFFE1FFFFFFFC0 2 | FFFFFFFE1FFFFFFFC0 3 | FFFFFFFE1FFFFFFFC0 4 | FFFFFFFE1FFFFFFFC0 5 | FFFFFFFE1FFFFFFFC0 6 | FFFFFFFE1FFFFFFFC0 7 | FFFFFFFE1FFFFFFFC0 8 | FFFFFFFE1FFFFFFFC0 9 | FFFFFFFE1FFFFFFFC0 10 | FFFFFFFE1FFFFFFFC0 11 | FFFFFFFE1FFFFFFFC0 12 | FFFFFFFE1FFFFFFFC0 13 | FFFFFFFE1FFFFFFFC0 14 | FFFFFFFE1FFFFFFFC0 15 | FFFC7FFE1FFF8FFFC0 16 | FFFC3FFE1FFF0FFFC0 17 | FFFC3FFE1FFF0FFFC0 18 | FFFC3FFE1FFF0FFFC0 19 | FFFC3FFE1FFF0FFFC0 20 | FFFC3FFE1FFF0FFFC0 21 | FFFC3FFE1FFF0FFFC0 22 | FFFC3FFE1FFF0FFFC0 23 | FFFC3FFE1FFF0FFFC0 24 | FFFC3FFE1FFF0FFFC0 25 | FFFC3FFE1FFF0FFFC0 26 | FFFC3FFE1FFF0FFFC0 27 | FFFC3FFE1FFF0FFFC0 28 | FFFC3FFE1FFF0FFFC0 29 | FFFC3FFE1FFF0FFFC0 30 | FFFC3FFE1FFF0FFFC0 31 | FFFC3FFE1FFF0FFFC0 32 | FFFC3FFE1FFF0FFFC0 33 | FFFC3FFE1FFF0FFFC0 34 | FFFC3FFE1FFF0FFFC0 35 | FFFC3FFE1FFF0FFFC0 36 | FFFC3FFE1FFF0FFFC0 37 | FFFC3FFE1FFF0FFFC0 38 | FFFC3FFE1FFF0FFFC0 39 | FFFC3FFE1FFF0FFFC0 40 | FFFC3FFE1FFF0FFFC0 41 | FFFC3FFE1FFF0FFFC0 42 | FFFC3FFE1FFF0FFFC0 43 | FFFC3FFE1FFF0FFFC0 44 | FFFC3FFE1FFF0FFFC0 45 | FFFC3FFE1FFF0FFFC0 46 | FFFC3FFE1FFF0FFFC0 47 | FFFC3FFE1FFF0FFFC0 48 | FFFC3FFE1FFF0FFFC0 49 | FFFC3FFE1FFF0FFFC0 50 | FFFC3FFE1FFF0FFFC0 51 | FFFC3FFE1FFF0FFFC0 52 | FFFC3FFE1FFF0FFFC0 53 | FFFC3FFFFFFF0FFFC0 54 | FFFC3FFFFFFF0FC3C0 55 | FFFC3FFFFFFF0F83C0 56 | FFFC3FFFFFFF0F83C0 57 | FFFC3FFFFFFF0F83C0 58 | FFFC3FFFFFFF0F83C0 59 | FFFC3FFFFFFF0F83C0 60 | FFFC3FFFFFFF0F83C0 61 | FFFC3FFFFFFF0FC7C0 62 | FFFC3FFFFFFF0FFFC0 63 | FFFC3FFFFFFF0FFFC0 64 | FFFC3FFFFFFF0FFFC0 65 | FFFC3FFFFFFF0FFFC0 66 | FFFC3FFFFFFF0FFFC0 67 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/img/upython_logo_s.txt: -------------------------------------------------------------------------------- 1 | FFFE3FFF80 2 | FFFE3FFF80 3 | FFFE3FFF80 4 | FFFE3FFF80 5 | FFFE3FFF80 6 | FFFE3FFF80 7 | FFFE3FFF80 8 | FE7E3F3F80 9 | FE7E3F3F80 10 | FE7E3F3F80 11 | FE7E3F3F80 12 | FE7E3F3F80 13 | FE7E3F3F80 14 | FE7E3F3F80 15 | FE7E3F3F80 16 | FE7E3F3F80 17 | FE7E3F3F80 18 | FE7E3F3F80 19 | FE7E3F3F80 20 | FE7E3F3F80 21 | FE7E3F3F80 22 | FE7E3F3F80 23 | FE7E3F3F80 24 | FE7E3F3F80 25 | FE7F7F3F80 26 | FE7F7F3F80 27 | FE7FFF3B80 28 | FE7FFF3180 29 | FE7FFF3180 30 | FE7FFF3180 31 | FE7FFF3B80 32 | FE7FFF3F80 33 | FE7FFF3F80 34 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/magic8_ball.py: -------------------------------------------------------------------------------- 1 | import time 2 | import urandom 3 | from console import Display, Button 4 | 5 | oled = Display() 6 | buttonSelect = Button(0) 7 | 8 | answers = [ 9 | "It is certain", 10 | "It is decidedly so", 11 | "Without a doubt", 12 | "Yes, definitely", 13 | "You may rely on it", 14 | "As I see it, yes", 15 | "Most likely", 16 | "Outlook good", 17 | "Yes", 18 | "Signs point to yes", 19 | "Reply hazy try again", 20 | "Ask again later", 21 | "Better not tell you now", 22 | "Cannot predict now", 23 | "Concentrate and ask again", 24 | "Don't count on it" 25 | "My reply is no", 26 | "My sources say no", 27 | "Outlook not so good", 28 | "Very doubtful"] 29 | 30 | def get_random_str(items): 31 | choise = urandom.getrandbits(5) 32 | try: 33 | s_return = items[choise] 34 | return s_return 35 | except IndexError: 36 | return get_random_str(items) 37 | 38 | def main(): 39 | oled.print_wrapped(" Magic 8 Ball ") 40 | time.sleep(1) 41 | 42 | while True: 43 | if not buttonSelect.is_released(): 44 | oled.clear(0, 1) 45 | time.sleep(1) 46 | oled.print_wrapped(get_random_str(answers)) 47 | 48 | main() -------------------------------------------------------------------------------- /projects/script_console/release/scripts/message_board.py: -------------------------------------------------------------------------------- 1 | import socket, os, gc, time, console 2 | 3 | file_name = "messages.txt" 4 | 5 | def check_file(): 6 | if file_name in os.listdir(): 7 | return True 8 | else: 9 | with open(file_name, "w") as f: 10 | f.close() 11 | return True 12 | 13 | def get_file_size(): 14 | with open(file_name, "r") as f: 15 | lines = f.readlines() 16 | f.close() 17 | return len(lines) 18 | 19 | def quick_decode(s_decode): 20 | 21 | elements = {"ñ": "%C3%B1", "€": "%E2,%AC", ";": "%3B", "?": "%3F", "/": "%2F", ":": "%3A", 22 | "#": "%23", "&": "%26", "=": "%3D", "+": "%2B", "$": "%24", ",": "%2C", "%": "%25", 23 | "<": "%3C", ">": "%3E", "@": "%40", "(": "%28", ")": "%29", "‚": "%82", "!": "%21"} 24 | if "+" in s_decode: 25 | s_decode = s_decode.replace("+", " ") 26 | if "%20" in s_decode: 27 | s_decode = s_decode.replace("%20", " ") 28 | for element in elements: 29 | if elements[element] in s_decode: 30 | s_decode = s_decode.replace(elements[element], element) 31 | return s_decode 32 | 33 | def write_file(message): 34 | if (message != "#") or (len(message) > 2): 35 | message = quick_decode(message) 36 | total_messages = read_file() 37 | if get_file_size() > 15: 38 | del total_messages[0] 39 | total_messages.append(message) 40 | with open(file_name, "w") as f: 41 | for item in total_messages: 42 | f.write(item + "\n") 43 | f.close() 44 | 45 | def read_file(): 46 | file_data = [] 47 | if check_file() is True: 48 | with open(file_name, "r") as messages: 49 | data = messages.readlines() 50 | if len(data) > 0: 51 | for line in data: 52 | message = line.rstrip() 53 | file_data.append(message) 54 | else: 55 | file_data.append("NO MESSAGES") 56 | return file_data 57 | 58 | def linted_data(): 59 | data = [] 60 | for element in read_file(): 61 | data.append("\n%s\n" % element) 62 | return data 63 | 64 | 65 | def main(): 66 | oled = console.Display() 67 | oled.print_wrapped("Checking messages file.") 68 | oled.clear(0, 1) 69 | time.sleep(1) 70 | check_file() 71 | html = """ 72 | 73 | 74 | Message board 75 | 76 | 77 | 91 | 92 | 93 |
94 |
95 |

Message board

96 |

97 |
98 | %s

Messages

99 |
100 |

Type a message:


101 |
102 |
103 |
104 | 117 | 118 | 119 | """ 120 | 121 | addr = socket.getaddrinfo("192.168.4.1", 80)[0][-1] 122 | s = socket.socket() 123 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 124 | s.bind(addr) 125 | s.listen(5) 126 | connection_count = 0 127 | 128 | while True: 129 | cl, addr = s.accept() 130 | oled.print_wrapped(str("Connection from : %s" % addr) + str("Free in: %d" % gc.mem_free())) 131 | time.sleep(0.1) 132 | oled.clear(0, 1) 133 | connection_count += 1 134 | cl_file = cl.makefile("rwb", 0) 135 | while True: 136 | h = cl_file.readline() 137 | gotten_msg = b"GET /?messageinput=" 138 | if gotten_msg in h: 139 | msg = h.decode("utf-8").split("/?messageinput=") 140 | final_msg = msg[1][:(len(msg)-12)] 141 | oled.clear(0, 1) 142 | oled.print_wrapped(final_msg) 143 | write_file(final_msg) 144 | if h == b"" or h == b"\r\n": 145 | break 146 | rows = linted_data() 147 | response = html % "\n".join(rows) 148 | try: 149 | cl.sendall(response) 150 | except OSError as error: 151 | print("Error trying to send all information. %s" % error) 152 | pass 153 | cl.close() 154 | oled.print_wrapped(str("Free out: %d" % gc.mem_free())) 155 | time.sleep(0.1) 156 | oled.clear(0, 1) 157 | 158 | if __name__ == "__main__": 159 | main() 160 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/rubber_duck_debugging.py: -------------------------------------------------------------------------------- 1 | import time 2 | import urandom 3 | from console import Display, Button 4 | 5 | oled = Display() 6 | buttonSelect = Button(0) 7 | 8 | questions = ["Which person around you could help you?", 9 | "Maybe you should consider refactoring?", 10 | "Have you tried step by step execution?", 11 | "Maybe some threads are unnecessary?", 12 | "Maybe you turn it off and on again?", 13 | "Could there be some race condition?", 14 | "Where is the lacking print()?", 15 | "Have you talked to your colleague?", 16 | "Why not call for a group meeting?", 17 | "Why not walk around your office?", 18 | "Should you really be doing this?", 19 | "Can the problem be broken down?", 20 | "Have you tried to unit test it?", 21 | "Maybe it is time for a coffee?", 22 | "Have you tried a clean build?", 23 | "Can you give me more details?", 24 | "Can this be hardware related?", 25 | "Could this not be your fault?", 26 | "Is this actually a problem?", 27 | "Can the code be simplified?", 28 | "Have you tried googling it?", 29 | "Maybe you can turn it on and off?", 30 | "I am not sure try again!", 31 | "Try again after having a coffee!", 32 | "Walk around the office and try again!", 33 | "Have you tried pair programming this?", 34 | "Maybe some of the threads are unnecessary?", 35 | "Can the problem be broken down more?", 36 | "Call for a group meeting to discuss this!", 37 | "Maybe you should consider some refactoring!", 38 | "Have you tried googling it?", 39 | "Why not try it again?"] 40 | 41 | def get_random_str(items): 42 | choise = urandom.getrandbits(5) 43 | try: 44 | s_return = items[choise] 45 | return s_return 46 | except IndexError: 47 | return get_random_str(items) 48 | 49 | def main(): 50 | oled.clear(1, 1) 51 | time.sleep(0.2) 52 | oled.clear(0, 1) 53 | 54 | while True: 55 | if not buttonSelect.is_released(): 56 | oled.clear(0, 1) 57 | time.sleep(1) 58 | oled.print_wrapped(get_random_str(questions)) 59 | 60 | main() -------------------------------------------------------------------------------- /projects/script_console/release/scripts/show_images.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | from console import Display 4 | 5 | 6 | def show(): 7 | 8 | oled = Display() 9 | 10 | available_img = [image for image in os.listdir() if image.endswith('.txt')] 11 | for image in available_img: 12 | oled.clear(0, 1) 13 | oled.draw_graphic(image, 35, 2) 14 | time.sleep(5) 15 | 16 | 17 | show() 18 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/simple_test.py: -------------------------------------------------------------------------------- 1 | import console, time 2 | 3 | keys = console.Keypad() 4 | display = console.Display() 5 | 6 | def center_text(txt): 7 | return '{: ^{}}'.format(txt, display.max_char) 8 | 9 | display.print_on_line(center_text("Wujuuu imported"), 0) 10 | display.print_on_line(center_text("Press the"), 3) 11 | display.print_on_line(center_text("button 0 to"), 4) 12 | display.print_on_line(center_text("count presses"), 5) 13 | intCounter = 0 14 | 15 | while True: 16 | buttons = keys.get_keypad() 17 | if buttons and buttons[3] == 0: 18 | intCounter += 1 19 | display.clear(0, 1) 20 | display.print_on_line(center_text("IT IS WORKING!!!"), 0) 21 | display.print_on_line(center_text("Button presses"), 3) 22 | display.print_on_line(center_text(str(intCounter)), 5) 23 | time.sleep_ms(250) 24 | if intCounter > 10: 25 | break 26 | -------------------------------------------------------------------------------- /projects/script_console/release/scripts/wifi_scanner.py: -------------------------------------------------------------------------------- 1 | import time 2 | import network 3 | import gc 4 | gc.enable() 5 | from console import Display 6 | 7 | class WiFiScanner: 8 | def __init__(self): 9 | self.name = '' 10 | self.strength = '' 11 | self.status = '' 12 | self.kanaal = '' 13 | self.oled = Display() 14 | self.wlan = network.WLAN(network.STA_IF) 15 | self.prepare_wifi() 16 | time.sleep_ms(5000) 17 | self.oled.print_wrapped("Performing scan...") 18 | time.sleep(0.5) 19 | self.oled.clear(0, 1) 20 | self.format() 21 | 22 | def prepare_wifi(self): 23 | if not self.wlan.active(): 24 | self.oled.print_wrapped("Turning the WiFi ON.") 25 | time.sleep(0.5) 26 | self.oled.clear(0, 1) 27 | self.wlan.active(True) 28 | elif self.wlan.active() and self.wlan.isconnected(): 29 | self.oled.print_wrapped("Disconnecting from WiFi connection.") 30 | time.sleep(0.5) 31 | self.oled.clear(0, 1) 32 | self.wlan.disconnect() 33 | 34 | def format(self): 35 | try: 36 | wlan_list = self.wlan.scan() 37 | except: 38 | wlan_list = [['NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE']] 39 | for counter in wlan_list: 40 | self.name = str(counter[0], 'utf8') 41 | self.strength = str(counter[3]) + ' dBm' 42 | self.kanaal = 'Channel: ' + str(counter[2]) 43 | self.status = self.get_secure(counter[4]) 44 | self.show_info() 45 | self.oled.clear(0, 1) 46 | 47 | @staticmethod 48 | def get_secure(num): 49 | s_return = "" 50 | try: 51 | if int(num) == 0: 52 | s_return = 'Open wifi' 53 | elif int(num) == 1: 54 | s_return = 'WEP' 55 | elif int(num) ==2: 56 | s_return = 'WPA-PSK' 57 | elif int(num) == 3: 58 | s_return = 'WPA2-PSK' 59 | elif int(num) == 4: 60 | s_return = 'WPA/WPA2-PSK' 61 | else: 62 | s_return = str("UNKNOWN %s" % num) 63 | 64 | return s_return 65 | except: 66 | return s_return 67 | 68 | def show_info(self): 69 | self.oled.clear(0, 1) 70 | if len(self.name) > 15: 71 | self.oled.print_on_line(self.name[0:15], 0) 72 | self.oled.print_on_line(self.name[15:int(len(self.name))], 1) 73 | else: 74 | self.oled.print_on_line(self.name, 0) 75 | 76 | self.oled.print_on_line(self.strength, 2, 30) 77 | self.oled.print_on_line(self.status, 3, 30) 78 | self.oled.print_on_line(self.kanaal, 4, 30) 79 | self.oled.print_on_line((str(gc.mem_free()) + " B"), 5, 30) 80 | time.sleep_ms(10000) 81 | 82 | ScannedWiFi = WiFiScanner() 83 | -------------------------------------------------------------------------------- /projects/turn_table/README.md: -------------------------------------------------------------------------------- 1 | # Turntable 2 | 3 | Online turntable, set the degrees, delay and count and hit SEND and you got yourself a WiFi controlled turntable. 4 | 5 | More? coming soon. 6 | 7 | # TODO: 8 | * Hardware 9 | * Proper release file 10 | * Images 11 | -------------------------------------------------------------------------------- /projects/turn_table/code/main.py: -------------------------------------------------------------------------------- 1 | import gc 2 | import time 3 | import socket 4 | 5 | from uln2003 import Stepper, FULL_ROTATION, HALF_STEP 6 | 7 | DIRECTION = 1 8 | SLOW = 5500 9 | FAST = 4000 10 | STATES = { 11 | 0: "Idle", 12 | 1: "Working" 13 | } 14 | STATE = STATES[0] 15 | ANGLE_STRING = b"angle=" 16 | DELAY_STRING = b"delay=" 17 | COUNT_STRING = b"count=" 18 | 19 | motor = Stepper(HALF_STEP, 15, 13, 12, 14, delay=FAST) 20 | 21 | 22 | def move_n_degrees(degrees, delay=0, count=1): 23 | """Perform a rotation on the motor n degrees n times. 24 | 25 | Also set the current state to `working` when performing the operations. 26 | 27 | Args: 28 | degrees: degrees to rotate. 29 | delay: time between each rotation. 30 | count: number of repetitions 31 | 32 | Returns: 33 | None. 34 | """ 35 | global STATE 36 | STATE = STATES[1] 37 | start = 1 if count > 1 else 0 38 | 39 | for index in range(start, count): 40 | motor.rel_angle(degrees) 41 | time.sleep(delay) 42 | STATE = STATES[0] 43 | 44 | 45 | def main(): 46 | global STATE 47 | addr = socket.getaddrinfo('192.168.4.1', 80)[0][-1] 48 | s = socket.socket() 49 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 50 | s.bind(addr) 51 | s.listen(5) 52 | 53 | html = """ 54 | 55 | 56 | Micro Turntable 57 | 58 | 59 | 75 | 76 | 77 |
78 |
79 |

Micro Turntable

80 |
81 |
82 |

Parameters:


83 | 84 | 85 | 86 | 87 |

Degrees

Delay

Count

88 |




89 |

Status:

%s

90 | 91 | 92 | """ 93 | 94 | connection_count = 0 95 | angle = 0 96 | delay = 0 97 | count = 0 98 | 99 | while True: 100 | cl, addr = s.accept() 101 | print(connection_count, "connection on", addr) 102 | print("Free in: %d" % gc.mem_free()) 103 | connection_count += 1 104 | cl_file = cl.makefile("rwb", 0) 105 | while True: 106 | h = cl_file.readline() 107 | print(h) 108 | # Parse headers to get the values. 109 | if ANGLE_STRING in h: 110 | try: 111 | angle = int(h.split(ANGLE_STRING)[1].split(b'&')[0]) 112 | STATE = STATES[1] 113 | except ValueError: 114 | angle = 0 115 | if DELAY_STRING in h: 116 | try: 117 | delay = int(h.split(DELAY_STRING)[1].split(b"&")[0]) 118 | except ValueError: 119 | delay = 0 120 | if COUNT_STRING in h: 121 | try: 122 | count = int(h.split(COUNT_STRING)[1].split(b" ")[0]) 123 | except ValueError: 124 | count = 0 125 | # Last header sent 126 | if h == b"" or h == b"\r\n": 127 | break 128 | 129 | response = html % "\n".join(STATE) 130 | 131 | try: 132 | cl.sendall(response) 133 | except OSError as error: 134 | print("Error trying to send all information. %s" % error) 135 | pass 136 | 137 | cl.close() 138 | print("Free out: %d" % gc.mem_free()) 139 | print("Got angle=%s, delay=%s and count=%s" % ( 140 | str(angle), str(delay), str(count) 141 | ) 142 | ) 143 | if angle > 0: 144 | move_n_degrees(angle, delay, count) 145 | # Reset the values. 146 | angle = 0 147 | delay = 0 148 | count = 0 149 | -------------------------------------------------------------------------------- /projects/turn_table/code/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 | Tell a stepper to move X many steps in a given direction 30 | """ 31 | def __init__(self, stepper, steps, direction=1): 32 | self.stepper = stepper 33 | self.steps = steps 34 | self.direction = direction 35 | 36 | 37 | class Driver: 38 | """ 39 | Drive a set of motors, each with their own commands 40 | """ 41 | 42 | @staticmethod 43 | def run(commands): 44 | """ 45 | Takes commands and calls the step function from the Stepper class in other to seem they are moving at the same time. 46 | 47 | Args: 48 | commands: List with the commands to execute. 49 | 50 | Returns: 51 | Nothing. 52 | """ 53 | 54 | # Work out total steps to take 55 | max_steps = sum([c.steps for c in commands]) 56 | 57 | count = 0 58 | while count != max_steps: 59 | for command in commands: 60 | # we want to interleave the commands 61 | if command.steps > 0: 62 | command.stepper.step(1, command.direction) 63 | command.steps -= 1 64 | count += 1 65 | 66 | 67 | class Stepper: 68 | def __init__(self, mode, pin1, pin2, pin3, pin4, delay=2000): 69 | self.mode = mode 70 | self.pin1 = machine.Pin(pin1, machine.Pin.OUT) 71 | self.pin2 = machine.Pin(pin2, machine.Pin.OUT) 72 | self.pin3 = machine.Pin(pin3, machine.Pin.OUT) 73 | self.pin4 = machine.Pin(pin4, machine.Pin.OUT) 74 | self.delay = delay # Recommend 10000+ for FULL_STEP, 1000 is OK for HALF_STEP 75 | self.steps_per_rev = FULL_ROTATION 76 | self.current_position = 0 77 | self.reset() # Initialize all to 0 78 | 79 | def step(self, step_count, direction=1): 80 | """ 81 | Rotates the Stepper motor a given number of steps. It also sets the current position of the stepper. 82 | 83 | Args: 84 | step_count: integer with the number of steps to do. 85 | direction: integer (1 or -1) for forward and backward direction. 86 | 87 | Returns: 88 | Nothing. 89 | """ 90 | for x in range(step_count): 91 | for bit in self.mode[::direction]: 92 | self.pin1.value(bit[0]) 93 | self.pin2.value(bit[1]) 94 | self.pin3.value(bit[2]) 95 | self.pin4.value(bit[3]) 96 | time.sleep_us(self.delay) 97 | self.current_position += (direction * step_count) 98 | 99 | def rel_angle(self, angle): 100 | """ 101 | Rotate stepper for given relative angle. 102 | 103 | Args: 104 | angle: Integer with the angle. 105 | 106 | Returns: 107 | Nothing. 108 | """ 109 | steps = int(angle / 360 * self.steps_per_rev) 110 | self.step(steps) 111 | 112 | def abs_angle(self, angle): 113 | """ 114 | Rotate stepper for given absolute angle since last power on. 115 | 116 | Args: 117 | angle: Integer with the angle. 118 | 119 | Returns: 120 | Nothing. 121 | """ 122 | steps = int(angle / 360 * self.steps_per_rev) 123 | steps -= self.current_position % self.steps_per_rev 124 | self.step(steps) 125 | 126 | def revolution(self, rev_count): 127 | """ 128 | Perform given number of full revolutions. 129 | 130 | Args: 131 | rev_count: Integer with the number of revolution to do. 132 | 133 | Returns: 134 | Nothing. 135 | """ 136 | self.step(rev_count * self.steps_per_rev) 137 | 138 | def set_step_delay(self, us): 139 | """ 140 | Set time in microseconds between each step. 141 | 142 | Args: 143 | us: integer with the number of microseconds. 144 | 145 | Returns: 146 | Nothing. 147 | """ 148 | if us < 20: # 20 us is the shortest possible for esp8266 149 | self.delay = 20 150 | else: 151 | self.delay = us 152 | 153 | def set_steps_per_revolution(self): 154 | """ 155 | Calculate the number of steps needed for one revolution. 156 | 157 | Returns: 158 | Nothing. 159 | """ 160 | self.steps_per_rev = int((360 / (5.625 / 64)) / len(self.mode)) 161 | 162 | def reset(self): 163 | """ 164 | Power off the motors and reset the steps count to zero. 165 | 166 | Returns: 167 | Nothing. 168 | """ 169 | self.pin1.value(0) 170 | self.pin2.value(0) 171 | self.pin3.value(0) 172 | self.pin4.value(0) 173 | if self.current_position > 0: 174 | self.current_position = 0 175 | -------------------------------------------------------------------------------- /projects/turn_table/release/main.py: -------------------------------------------------------------------------------- 1 | import gc 2 | import time 3 | import socket 4 | from uln2003 import Stepper, FULL_ROTATION, HALF_STEP 5 | DIRECTION = 1 6 | SLOW = 5500 7 | FAST = 4000 8 | STATES = { 9 | 0: "Idle", 10 | 1: "Working" 11 | } 12 | STATE = STATES[0] 13 | ANGLE_STRING = b"angle=" 14 | DELAY_STRING = b"delay=" 15 | COUNT_STRING = b"count=" 16 | motor = Stepper(HALF_STEP, 15, 13, 12, 14, delay=FAST) 17 | def move_n_degrees(degrees, delay=0, count=1): 18 | global STATE 19 | STATE = STATES[1] 20 | start = 1 if count > 1 else 0 21 | 22 | for index in range(start, count): 23 | motor.rel_angle(degrees) 24 | time.sleep(delay) 25 | STATE = STATES[0] 26 | def main(): 27 | global STATE 28 | addr = socket.getaddrinfo('192.168.4.1', 80)[0][-1] 29 | s = socket.socket() 30 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 31 | s.bind(addr) 32 | s.listen(5) 33 | html = """ 34 | 35 | 36 | Micro Turntable 37 | 38 | 39 | 55 | 56 | 57 |
58 |
59 |

Parameters:


60 | 61 | 62 | 63 |

Degrees

Delay

Count





64 |

Status:

%s

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 | Wemos d1 mini board 17 |

18 | 19 | - **OLED display (I2C)** 20 | 21 |

22 | Wemos D1 Oled Display 23 |

24 | 25 | - **DHT11 Humidity sensor.** 26 | 27 |

28 | DHT11 sensor 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 | Drawing 9 |

10 | 11 | ## Parts needed: 12 | 13 | - ESP8266 14 | 15 | I'm using the Wemos D1 Mini board. 16 | 17 |

18 | Wemos d1 mini board 19 |

20 | 21 | - DHT11 Sensor 22 | 23 |

24 | DHT11 Sensor 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 | %s

Temperature

Humidity

56 |
57 |

NOTE: This page will automatically refresh every 30 seconds.

58 |
59 | 72 | 73 | 74 | """ 75 | addr = socket.getaddrinfo('192.168.4.1', 80)[0][-1] 76 | s = socket.socket() 77 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 78 | s.bind(addr) 79 | s.listen(5) 80 | 81 | while True: 82 | cl, addr = s.accept() 83 | print('Client connected from', addr) 84 | print("Free in: %d" % gc.mem_free()) 85 | cl_file = cl.makefile('rwb', 0) 86 | while True: 87 | h = cl_file.readline() 88 | if h == b"" or h == b"\r\n": 89 | break 90 | rows = read_sensors() 91 | response = html % '\n'.join(rows) 92 | try: 93 | cl.sendall(response) 94 | except OSError as error: 95 | print("Error trying to send all information. %s" % error) 96 | pass 97 | cl.close() 98 | 99 | main() 100 | -------------------------------------------------------------------------------- /projects/weather_station/release/weather_station.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import dht 3 | import gc 4 | import machine 5 | 6 | def read_sensors(): 7 | data = [] 8 | d = dht.DHT11(machine.Pin(2)) 9 | d.measure() 10 | temperature = d.temperature() 11 | humidity = d.humidity() 12 | for i in range(0, 1): 13 | data.append('

%s C

%s %

' % (str(temperature), str(humidity))) 14 | return data 15 | 16 | def main(): 17 | html = b""" 18 | 19 | 20 | Weather Station 21 | 22 | 23 | 24 | 33 | 34 | 35 |
36 |
37 |

ESP8266 Weather Station


38 |

39 |
40 |
41 | %s

Temperature

Humidity

42 |
43 |

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 |

Header 1

37 |

Header 2

38 | 39 | 40 | -------------------------------------------------------------------------------- /static/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title for page 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

Header 1

15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
Table Header 1Table Header 2
Data 1 Data 2
25 |
26 |
27 |

Type a message:


28 | Input message 29 | Send 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /static/images/12_neopixel_ring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/12_neopixel_ring.png -------------------------------------------------------------------------------- /static/images/DHT11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/DHT11.png -------------------------------------------------------------------------------- /static/images/bulleting_board_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/bulleting_board_index.png -------------------------------------------------------------------------------- /static/images/d-duino-pins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/d-duino-pins.png -------------------------------------------------------------------------------- /static/images/dht11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/dht11.png -------------------------------------------------------------------------------- /static/images/photos/msc_oled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/msc_oled.png -------------------------------------------------------------------------------- /static/images/photos/print_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/print_test.png -------------------------------------------------------------------------------- /static/images/photos/python_oled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/python_oled.png -------------------------------------------------------------------------------- /static/images/photos/upython_oled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/upython_oled.png -------------------------------------------------------------------------------- /static/images/photos/upython_oled_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/upython_oled_s.png -------------------------------------------------------------------------------- /static/images/photos/wifi_scan1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/wifi_scan1.jpg -------------------------------------------------------------------------------- /static/images/photos/wifi_scan2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/wifi_scan2.jpg -------------------------------------------------------------------------------- /static/images/photos/wifi_scan3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/photos/wifi_scan3.jpg -------------------------------------------------------------------------------- /static/images/push_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/push_button.png -------------------------------------------------------------------------------- /static/images/weather_station_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/weather_station_index.png -------------------------------------------------------------------------------- /static/images/wemos_d1_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/wemos_d1_mini.png -------------------------------------------------------------------------------- /static/images/wemos_mini_oled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/wemos_mini_oled.png -------------------------------------------------------------------------------- /static/images/wemos_pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/wemos_pinout.jpg -------------------------------------------------------------------------------- /static/images/witty-cloud.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/witty-cloud.jpg -------------------------------------------------------------------------------- /static/images/witty-schematics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeyeto2788/MicroPythonScripts/740f799fa72e11276c986e1833da33e6cfefc8f1/static/images/witty-schematics.jpg -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | ## Tools available 4 | 5 | - `generate_releases.py` (WIP) 6 | Loop through all projects available on this repository and convert the files on the `code` folders into a stripped and short file with less characters, and create a `.zip` folder with all of them. 7 | 8 | - `uncommend_and_upload.py` (DONE) 9 | Delete comments and try to make the scripts smaller and upload it to the board. 10 | 11 | ## Requirements 12 | 13 | All needed requirements are listed on the `requirements.txt` file placed on this folder. 14 | 15 | To use the tools just install them by executing the following commands from the root path of this cloned repository: 16 | 17 | ```shell 18 | cd ./tools 19 | pip install -r requirements.txt 20 | chmod +x ./*.py 21 | ``` 22 | -------------------------------------------------------------------------------- /tools/generate_releases.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import argparse 3 | import os 4 | import shutil 5 | import zipfile 6 | 7 | log = False 8 | 9 | 10 | def verbose(*arguments, **kwargs): 11 | """Dummy function to log output on commands if needed.""" 12 | global log 13 | 14 | if log: 15 | print(*arguments, **kwargs) 16 | 17 | 18 | def get_release_files(projects_dir: str) -> dict: 19 | """Walk over the repo and find the release files. 20 | 21 | It will look over the folder named 'release' all files within that folder. 22 | 23 | Args: 24 | projects_dir: Directory where to look files in. 25 | 26 | Returns: 27 | Dictionary containing the following structure: 28 | 'project_name':{ 29 | 'file1.ext': { 30 | 'from': 'dir/from/which/to/copy/file/from' 31 | 'to': ''dir/from/which/to/copy/file/to'' 32 | } 33 | } 34 | """ 35 | destination = '' 36 | project_release = dict() 37 | 38 | for root_dir, directories, files in os.walk(projects_dir): 39 | 40 | if root_dir.endswith('release'): 41 | project_name = os.path.basename(os.path.dirname(root_dir)) 42 | project_release[project_name] = dict() 43 | 44 | for file in files: 45 | project_release[project_name][file] = dict() 46 | original_file_dir = os.path.join(root_dir, file) 47 | project_release[project_name][file]["from"] = original_file_dir 48 | filename = os.path.basename(original_file_dir) 49 | destination_dir = os.path.join(destination, project_name, filename) 50 | project_release[project_name][file]["to"] = destination_dir 51 | 52 | return project_release 53 | 54 | 55 | def generate_zip(files: list, destination: str): 56 | """Iterate over the list of files copied and generate a zip files with them""" 57 | verbose("-" * 20) 58 | verbose("Zipping files.".upper()) 59 | zip_dir = os.path.join(destination, 'release.zip') 60 | 61 | with zipfile.ZipFile(zip_dir, 'w') as zip_obj: 62 | for file in files: 63 | inner_filename = os.path.join( 64 | os.path.basename(os.path.dirname(file)), 65 | os.path.basename(file) 66 | ) 67 | verbose(f"Adding '{inner_filename}' into zip.") 68 | zip_obj.write( 69 | file, 70 | arcname=inner_filename 71 | ) 72 | verbose("Done Zipping files.".upper()) 73 | 74 | 75 | def copy_files(data: dir, destination: str): 76 | files_copied = list() 77 | verbose("-" * 20) 78 | verbose("Copying files:".upper()) 79 | 80 | for _, project_files in data.items(): 81 | for _, files in project_files.items(): 82 | destination_dir = os.path.join(destination, files['to']) 83 | os.makedirs(os.path.dirname(destination_dir), exist_ok=True) 84 | verbose(f"Copying file '{files['from']}' to '{destination_dir}'") 85 | shutil.copyfile(files['from'], destination_dir) 86 | files_copied.append(destination_dir) 87 | verbose("Done copying.".upper()) 88 | 89 | return files_copied 90 | 91 | 92 | def print_data(data: dict): 93 | print(f"We found '{len(data.keys())}' projects.\n") 94 | 95 | for project, files in data.items(): 96 | print(f"'{project}' project has the following files:") 97 | [print(f"\t{file}") for file in files.keys()] 98 | 99 | 100 | def main(options): 101 | global log 102 | repo_dir = os.path.dirname( 103 | os.path.dirname(os.path.abspath(__file__)) 104 | ) 105 | projects_dir = os.path.abspath(os.path.join(repo_dir, 'projects')) 106 | 107 | if options.verbose: 108 | log = True 109 | # Get all project release files. 110 | data = get_release_files(projects_dir) 111 | print_data(data) 112 | copied_files = None 113 | 114 | if options.output != "": 115 | destination = os.path.abspath(options.output) 116 | # Check if directory exists or not. 117 | if not os.path.exists(destination): 118 | 119 | try: 120 | verbose("-" * 20) 121 | verbose(f"Creating '{destination}' directory.") 122 | os.makedirs(destination, exist_ok=True) 123 | except Exception as exe_error: 124 | verbose("Something went wrong trying to create the destination directory.") 125 | raise exe_error 126 | # Only copy files if directory exists or if 127 | # no problem found creating destination directory. 128 | copied_files = copy_files(data, destination) 129 | 130 | if options.zip: 131 | # Check if there is at least one file copied in order 132 | # to invoke the zipping process. 133 | if copied_files is not None: 134 | generate_zip(copied_files, destination) 135 | 136 | 137 | if __name__ == '__main__': 138 | 139 | parser = argparse.ArgumentParser( 140 | description='Script to generate the release of the projects so it can be easily upload' 141 | 'to the boards.') 142 | 143 | parser.add_argument('-o', '--output', action='store', nargs='?', 144 | default='', type=str, help='Output directory.') 145 | parser.add_argument('-z', '--zip', action='store', nargs='?', 146 | default=False, type=bool, help='Make zip file.') 147 | parser.add_argument('-v', '--verbose', action='store', nargs='?', 148 | default=False, type=bool, help='Verbose output.') 149 | 150 | args = parser.parse_args() 151 | 152 | try: 153 | main(options=args) 154 | exit(0) 155 | 156 | except Exception as exec_error: 157 | print(f"An error has occurred: {exec_error}\nArgs used: {args}") 158 | print('\n\nPlease review usage of the application below.') 159 | print(parser.print_help()) 160 | exit(-1) 161 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | pylint==2.3.1 2 | pyminifier==2.1 3 | adafruit-ampy==1.0.7 4 | --------------------------------------------------------------------------------