├── LICENSE.txt ├── README.md ├── Source_Ch02 ├── example1_blue_led.py ├── example2_blink_leds.py ├── example3_button.py ├── file_io.py └── log.txt ├── Source_Ch03 └── CC3K.py ├── Source_Ch04 ├── challenges │ └── conversions.py ├── conversions.py ├── fibonacci.py ├── my_data.json ├── pickup.py ├── pickup_truck.py ├── roman.py ├── roman_numerals.py ├── rw_json.py ├── sedan.py └── vehicle.py ├── Source_Ch05 ├── data.bin ├── exception_example.py ├── import_errors.py ├── my_helper │ ├── __init__.py │ ├── helper_functions.py │ └── sensor_convert.py ├── my_vehicles.json ├── sys_example.py ├── uio_example.py ├── ujson_example.py ├── uos_example.py ├── utime_example.py └── wipy_ntp.py ├── Source_Ch06 ├── pyboard_SPI.py ├── pyboard_accel.py ├── pyboard_button.py ├── pyboard_lcd.py ├── secret_log.txt ├── wipy_RGB.py ├── wipy_encryption.py └── wipy_heartbeat.py ├── Source_Ch08 ├── Pyboard │ ├── clock.py │ ├── main.py │ ├── ssd1306.py │ └── urtc.py ├── WiPy │ ├── clock.py │ ├── main.py │ ├── ssd1306.py │ └── urtc.py ├── clock_pyb_wipy.diff ├── oled_test.py ├── rtc_test.py ├── ssd1306_pyb.diff ├── ssd1306_wipy.diff └── urtc_pyboard.diff ├── Source_Ch09 ├── Pyboard │ ├── ped_part1_pyb.py │ └── ped_part2_pyb.py ├── WiPy │ ├── ped_part1_wipy.py │ └── ped_part2_wipy.py └── response.html ├── Source_Ch10 ├── Pyboard │ ├── plant_monitor.py │ └── plant_pyboard.py ├── WiPy │ ├── plant_monitor.py │ └── plant_wipy.py ├── part1.html ├── part2.html ├── plant_data.csv ├── sample.html └── threshold.py ├── Source_Ch11 ├── weather.csv ├── weather.py └── weather_node.py └── contributing.md /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/micropython-for-internet-of-things/c769013c4ea965375bda1964efdbede8489d4a1f/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*MicroPython for the Internet of Things*](http://www.apress.com/9781484231227) by Charles Bell (Apress, 2017). 4 | 5 | [comment]: #cover 6 | 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. 17 | -------------------------------------------------------------------------------- /Source_Ch02/example1_blue_led.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example 1 5 | # 6 | # Turn on the blue LED (4 = Blue) 7 | # 8 | # Dr. Charles Bell 9 | # 10 | import pyb # Import the Pyboard library 11 | 12 | led = pyb.LED(4) # Get the LED instance 13 | led.off() # Make sure it's off first 14 | 15 | for i in range(1, 20): # Run the indented code 20 times 16 | led.on() # Turn LED on 17 | pyb.delay(250) # Wait for 250 milleseconds 18 | led.off() # Turn LED off 19 | pyb.delay(250) # Wait for 250 milleseconds 20 | 21 | led.off() # Turn the LED off at the end 22 | print("Done!") # Goodbye! 23 | -------------------------------------------------------------------------------- /Source_Ch02/example2_blink_leds.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example 2 5 | # 6 | # Turn on the four LEDs on the board in order 7 | # 8 | # 1 = Red 9 | # 2 = Green 10 | # 3 = Orange 11 | # 4 = Blue 12 | # 13 | # Dr. Charles Bell 14 | # 15 | import pyb # Import the Pyboard library 16 | 17 | for j in range(1, 4): # Turn off all of the LEDs 18 | led = pyb.LED(j) # Get the LED 19 | led.off() # Turn the LED off 20 | 21 | i = 1 # LED counter 22 | while True: # Loop forever 23 | led = pyb.LED(i) # Get next LED 24 | led.on() # Turn LED on 25 | pyb.delay(500) # Wait for 1/2 second 26 | led.off() # Turn LED off 27 | pyb.delay(500) # Wait for 1/2 second 28 | i = i + 1 # Increment the LED counter 29 | if i > 4: # If > 4, start over at 1 30 | i = 1 31 | 32 | -------------------------------------------------------------------------------- /Source_Ch02/example3_button.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example 3 5 | # 6 | # Flash the green LED when button is pushed 7 | # 8 | # Dr. Charles Bell 9 | # 10 | import pyb # Import the Pyboard library 11 | led = pyb.LED(2) # Get LED instance (2 = green) 12 | led.off() # Make sure the LED if off 13 | 14 | # Setup a callback function to handle button pressed 15 | # using an interrupt service routine 16 | def flash_led(): 17 | for i in range(1, 25): 18 | led.on() 19 | pyb.delay(100) 20 | led.off() 21 | pyb.delay(100) 22 | 23 | button = pyb.Switch() # Get the button (switch) 24 | button.callback(flash_led) # Register the callback (ISR) 25 | 26 | print("Ready for testing!") 27 | 28 | -------------------------------------------------------------------------------- /Source_Ch02/file_io.py: -------------------------------------------------------------------------------- 1 | # Example code to demonstrate writing and reading data to/from files 2 | 3 | # Step 1: Create a file and write some data 4 | new_file = open("log.txt", "w") # use "write" mode 5 | new_file.write("1,apples,2.5\n") # write some data 6 | new_file.write("2,oranges,1\n") # write some data 7 | new_file.write("3,peaches,3\n") # write some data 8 | new_file.write("4,grapes,21\n") # write some data 9 | new_file.close() # close the file 10 | 11 | # Step 2: Open a file and read data 12 | old_file = open("log.txt", "r") # use "read" mode 13 | # Use a loop to read all rows in the file 14 | for row in old_file.readlines(): 15 | columns = row.strip("\n").split(",") # split row by commas 16 | print(" : ".join(columns)) # print the row with colon separator 17 | old_file.close() 18 | -------------------------------------------------------------------------------- /Source_Ch02/log.txt: -------------------------------------------------------------------------------- 1 | 1,apples,2.5 2 | 2,oranges,1 3 | 3,peaches,3 4 | 4,grapes,21 5 | -------------------------------------------------------------------------------- /Source_Ch03/CC3K.py: -------------------------------------------------------------------------------- 1 | # connect/ show IP config a specific network interface 2 | import network 3 | import pyb 4 | 5 | def test_connect(): 6 | nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3) 7 | nic.connect('YOUR_ROUTER_HERE', 'YOUR_ROUTER_PASSWORD_HERE') 8 | while not nic.isconnected(): 9 | pyb.delay(50) 10 | print(nic.ifconfig()) 11 | 12 | # now use usocket as usual 13 | import usocket as socket 14 | addr = socket.getaddrinfo('micropython.org', 80)[0][-1] 15 | s = socket.socket() 16 | s.connect(addr) 17 | s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n') 18 | data = s.recv(1000) 19 | print(data) 20 | s.close() -------------------------------------------------------------------------------- /Source_Ch04/challenges/conversions.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Challenge Example: Convert integer to binary, hex, and octal 5 | # 6 | # Dr. Charles Bell 7 | # 8 | import argparse 9 | # Setup the argument parser 10 | parser = argparse.ArgumentParser() 11 | # We need two arguments: integer, and conversion 12 | parser.add_argument("original_val", help="Value to convert.") 13 | parser.add_argument("conversion", help="Conversion: hex, bin, or oct.") 14 | # Get the arguments 15 | args = parser.parse_args() 16 | # Convert string to integer 17 | value = int(args.original_val) 18 | if args.conversion == 'bin': 19 | print("{0} in binary is {1}".format(value, bin(value))) 20 | elif args.conversion == 'oct': 21 | print("{0} in octal is {1}".format(value, oct(value))) 22 | elif args.conversion == 'hex': 23 | print("{0} in hexadecimal is {1}".format(value, hex(value))) 24 | else: 25 | print("Sorry, I don't understand, {0}.".format(args.conversion)) 26 | -------------------------------------------------------------------------------- /Source_Ch04/conversions.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example: Convert integer to binary, hex, and octal 5 | # 6 | # Dr. Charles Bell 7 | # 8 | 9 | # Create a tuple of integer values 10 | values = (12, 450, 1, 89, 2017, 90125) 11 | 12 | # Loop through the values and convert each to binary, hex, and octal 13 | for value in values: 14 | print("{0} in binary is {1}".format(value, bin(value))) 15 | print("{0} in octal is {1}".format(value, oct(value))) 16 | print("{0} in hexadecimal is {1}".format(value, hex(value))) 17 | 18 | -------------------------------------------------------------------------------- /Source_Ch04/fibonacci.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example: Fibonacci series using recursion 5 | # 6 | # Calculate the Fibonacci series based on user input 7 | # 8 | # Dr. Charles Bell 9 | # 10 | 11 | # Create a function to calculate Fibonacci series (iterative) 12 | # Returns a list. 13 | def fibonacci_iterative(count): 14 | i = 1 15 | if count == 0: 16 | fib = [] 17 | elif count == 1: 18 | fib = [1] 19 | elif count == 2: 20 | fib = [1,1] 21 | elif count > 2: 22 | fib = [1,1] 23 | while i < (count - 1): 24 | fib.append(fib[i] + fib[i-1]) 25 | i += 1 26 | return fib 27 | 28 | # Create a function to calculate the nth Fibonacci number (recursive) 29 | # Returns an integer. 30 | def fibonacci_recursive(number): 31 | if number == 0: 32 | return 0 33 | elif number == 1: 34 | return 1 35 | else: 36 | # Call our self counting down. 37 | value = fibonacci_recursive(number-1) + fibonacci_recursive(number-2) 38 | return value 39 | 40 | # Main code 41 | print("Welcome to my Fibonacci calculator!") 42 | index = int(input("Please enter the number of integers in the series: ")) 43 | 44 | # Recursive example 45 | print("We calculate the value using a recursive algoritm.") 46 | nth_fibonacci = fibonacci_recursive(index) 47 | print("The {0}{1} fibonacci number is {2}." 48 | "".format(index, "th" if index > 1 else "st", nth_fibonacci)) 49 | see_series = str(input("Do you want to see all of the values in the series? ")) 50 | if see_series in ["Y","y"]: 51 | series = [] 52 | for i in range(1,index+1): 53 | series.append(fibonacci_recursive(i)) 54 | print("Series: {0}: ".format(series)) 55 | 56 | # Iterative example 57 | print("We calculate the value using an iterative algoritm.") 58 | series = fibonacci_iterative(index) 59 | print("The {0}{1} fibonacci number is {2}." 60 | "".format(index, "th" if index > 1 else "st", series[index-1])) 61 | see_series = str(input("Do you want to see all of the values in the series? ")) 62 | if see_series in ["Y","y"]: 63 | print("Series: {0}: ".format(series)) 64 | print("bye!") 65 | -------------------------------------------------------------------------------- /Source_Ch04/my_data.json: -------------------------------------------------------------------------------- 1 | {"age": 6, "breed": "dachshund", "type": "dog", "name": "Violet"} 2 | {"age": 15, "breed": "poodle", "type": "dog", "name": "JonJon"} 3 | {"age": 4, "breed": "siberian khatru", "type": "cat", "name": "Mister"} 4 | {"age": 7, "breed": "koi", "type": "fish", "name": "Spot"} 5 | {"age": 6, "breed": "dachshund", "type": "dog", "name": "Charlie"} 6 | -------------------------------------------------------------------------------- /Source_Ch04/pickup.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Class Example: Exeercising the PickupTruck class. 5 | # 6 | # Dr. Charles Bell 7 | # 8 | from pickup_truck import PickupTruck 9 | 10 | pickup = PickupTruck(500) 11 | pickup.add_occupant() 12 | pickup.add_occupant() 13 | pickup.add_occupant() 14 | pickup.add_occupant() 15 | pickup.add_payload(100) 16 | pickup.add_payload(300) 17 | print("Number of occupants in truck = {0}.".format(pickup.num_occupants())) 18 | print("Weight in truck = {0}.".format(pickup.get_payload())) 19 | pickup.add_payload(200) 20 | pickup.remove_payload(400) 21 | pickup.remove_payload(10) 22 | 23 | print("PickupTruck.__doc__:", PickupTruck.__doc__) 24 | print("PickupTruck.__name__:", PickupTruck.__name__) 25 | print("PickupTruck.__module__:", PickupTruck.__module__) 26 | print("PickupTruck.__bases__:", PickupTruck.__bases__) 27 | print("PickupTruck.__dict__:", PickupTruck.__dict__) 28 | 29 | -------------------------------------------------------------------------------- /Source_Ch04/pickup_truck.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Class Example: Inheriting the Vehicle class to form a 5 | # model of a pickup truck with maximum occupants and maximum 6 | # payload. 7 | # 8 | # Dr. Charles Bell 9 | # 10 | from vehicle import Vehicle 11 | 12 | class PickupTruck(Vehicle): 13 | """This is a pickup truck that has: 14 | axles = 2, 15 | doors = 2, 16 | __max occupants = 3 17 | The maximum payload is set on instantiation. 18 | """ 19 | occupants = 0 20 | payload = 0 21 | max_payload = 0 22 | __max_occupants = 3 23 | 24 | def __init__(self, max_weight): 25 | super().__init__(2,2) 26 | self.max_payload = max_weight 27 | 28 | def add_occupant(self): 29 | if (self.occupants < self.__max_occupants): 30 | super().add_occupant() 31 | else: 32 | print("Sorry, only 3 occupants are permitted in the truck.") 33 | 34 | def add_payload(self, num_pounds): 35 | if ((self.payload + num_pounds) < self.max_payload): 36 | self.payload += num_pounds 37 | else: 38 | print("Overloaded!") 39 | 40 | def remove_payload(self, num_pounds): 41 | if ((self.payload - num_pounds) >= 0): 42 | self.payload -= num_pounds 43 | else: 44 | print("Nothing in the truck.") 45 | 46 | def get_payload(self): 47 | return self.payload 48 | -------------------------------------------------------------------------------- /Source_Ch04/roman.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example: Convert roman numerals using a class 5 | # 6 | # Convert integers to roman numerals 7 | # Convert roman numerals to integers 8 | # 9 | # Dr. Charles Bell 10 | # 11 | 12 | from roman_numerals import Roman_Numerals 13 | 14 | roman_str = input("Enter a valid roman numeral: ") 15 | roman_num = Roman_Numerals() 16 | 17 | # Convert to roman numberals 18 | value = roman_num.convert_to_int(roman_str) 19 | print("Convert to integer: {0} = {1}".format(roman_str, value)) 20 | 21 | # Convert to integer 22 | new_str = roman_num.convert_to_roman(value) 23 | print("Convert to Roman Numerals: {0} = {1}".format(value, new_str)) 24 | 25 | print("bye!") 26 | -------------------------------------------------------------------------------- /Source_Ch04/roman_numerals.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example: Roman numerals class 5 | # 6 | # Convert integers to roman numerals 7 | # Convert roman numerals to integers 8 | # 9 | # Dr. Charles Bell 10 | # 11 | 12 | class Roman_Numerals: 13 | 14 | # Private dictionary of roman numerals 15 | __roman_dict = { 16 | 'I': 1, 17 | 'IV': 4, 18 | 'V': 5, 19 | 'IX': 9, 20 | 'X': 10, 21 | 'XL': 40, 22 | 'L': 50, 23 | 'XC': 90, 24 | 'C': 100, 25 | 'CD': 400, 26 | 'D': 500, 27 | 'CM': 900, 28 | 'M': 1000, 29 | } 30 | 31 | def convert_to_int(self, roman_num): 32 | value = 0 33 | for i in range(len(roman_num)): 34 | if i > 0 and self.__roman_dict[roman_num[i]] > self.__roman_dict[roman_num[i - 1]]: 35 | value += self.__roman_dict[roman_num[i]] - 2 * self.__roman_dict[roman_num[i - 1]] 36 | else: 37 | value += self.__roman_dict[roman_num[i]] 38 | return value 39 | 40 | def convert_to_roman(self, int_value): 41 | # First, get the values of all of entries in the dictionary 42 | roman_values = list(self.__roman_dict.values()) 43 | roman_keys = list(self.__roman_dict.keys()) 44 | # Prepare the string 45 | roman_str = "" 46 | remainder = int_value 47 | # Loop through the values in reverse 48 | for i in range(len(roman_values)-1, -1, -1): 49 | count = int(remainder / roman_values[i]) 50 | if count > 0: 51 | for j in range(0,count): 52 | roman_str += roman_keys[i] 53 | remainder -= count * roman_values[i] 54 | return roman_str 55 | 56 | -------------------------------------------------------------------------------- /Source_Ch04/rw_json.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Example: Storing and retrieving JSON objects in files 5 | # 6 | # Dr. Charles Bell 7 | # 8 | 9 | import json 10 | 11 | # Prepare a list of JSON documents for pets by converting JSON to a dictionary 12 | pets = [] 13 | parsed_json = json.loads('{"name":"Violet", "age": 6, "breed":"dachshund", "type":"dog"}') 14 | pets.append(parsed_json) 15 | parsed_json = json.loads('{"name": "JonJon", "age": 15, "breed":"poodle", "type":"dog"}') 16 | pets.append(parsed_json) 17 | parsed_json = json.loads('{"name": "Mister", "age": 4, "breed":"siberian khatru", "type":"cat"}') 18 | pets.append(parsed_json) 19 | parsed_json = json.loads('{"name": "Spot", "age": 7, "breed":"koi", "type":"fish"}') 20 | pets.append(parsed_json) 21 | parsed_json = json.loads('{"name": "Charlie", "age": 6, "breed":"dachshund", "type":"dog"}') 22 | pets.append(parsed_json) 23 | 24 | # Now, write these entries to a file. Note: overwrites the file 25 | json_file = open("my_data.json", "w") 26 | for pet in pets: 27 | json_file.write(json.dumps(pet)) 28 | json_file.write("\n") 29 | json_file.close() 30 | 31 | # Now, let's read the JSON documents then print the name and age for all of the dogs in the list 32 | my_pets = [] 33 | json_file = open("my_data.json", "r") 34 | for pet in json_file.readlines(): 35 | parsed_json = json.loads(pet) 36 | my_pets.append(parsed_json) 37 | json_file.close() 38 | 39 | print("Name, Age") 40 | for pet in my_pets: 41 | if pet['type'] == 'dog': 42 | print("{0}, {1}".format(pet['name'], pet['age'])) 43 | 44 | 45 | -------------------------------------------------------------------------------- /Source_Ch04/sedan.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Class Example: Using the generic Vehicle class 5 | # 6 | # Dr. Charles Bell 7 | # 8 | from vehicle import Vehicle 9 | 10 | sedan = Vehicle(2, 4) 11 | sedan.add_occupant() 12 | sedan.add_occupant() 13 | sedan.add_occupant() 14 | print("The car has {0} occupants.".format(sedan.num_occupants())) 15 | -------------------------------------------------------------------------------- /Source_Ch04/vehicle.py: -------------------------------------------------------------------------------- 1 | # 2 | # MicroPython for the IOT 3 | # 4 | # Class Example: A generic vehicle 5 | # 6 | # Dr. Charles Bell 7 | # 8 | class Vehicle: 9 | """Base class for defining vehicles""" 10 | axles = 0 11 | doors = 0 12 | occupants = 0 13 | 14 | def __init__(self, num_axles, num_doors): 15 | self.axles = num_axles 16 | self.doors = num_doors 17 | 18 | def get_axles(self): 19 | return self.axles 20 | 21 | def get_doors(self): 22 | return self.doors 23 | 24 | def add_occupant(self): 25 | self.occupants += 1 26 | 27 | def num_occupants(self): 28 | return self.occupants -------------------------------------------------------------------------------- /Source_Ch05/data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/micropython-for-internet-of-things/c769013c4ea965375bda1964efdbede8489d4a1f/Source_Ch05/data.bin -------------------------------------------------------------------------------- /Source_Ch05/exception_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of exceptions 3 | values = [] 4 | print("Start sensor read.") 5 | try: 6 | values.append(read_sensor(pin11)) 7 | values.append(read_sensor(pin12)) 8 | values.append(read_sensor(pin13)) 9 | values.append(read_sensor(pin17)) 10 | values.append(read_sensor(pin18)) 11 | except ValueError as err: 12 | print("WARNING: One or more sensors valued to read a correct value.", err) 13 | else: 14 | print("ERROR: fatal error reading sensors.") 15 | finally: 16 | print("Sensor read complete.") 17 | -------------------------------------------------------------------------------- /Source_Ch05/import_errors.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Try to import the keys() function from piano 3 | try: 4 | from piano import keys 5 | except ImportError as err: 6 | print("WARNING:", err) 7 | def keys(): 8 | return(['A','B','C','D','E','F','G']) 9 | 10 | print("Keys:", keys()) 11 | -------------------------------------------------------------------------------- /Source_Ch05/my_helper/__init__.py: -------------------------------------------------------------------------------- 1 | # Metadata 2 | __name__ = "Chuck's Python Helper Library" 3 | __all__ = ['format_time', 'get_rand', 'get_moisture_level'] 4 | # Library-level imports 5 | from my_helper.helper_functions import format_time, get_rand 6 | from my_helper.sensor_convert import get_moisture_level 7 | -------------------------------------------------------------------------------- /Source_Ch05/my_helper/helper_functions.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example module for the my_helper library 3 | # This module contains helper functions for general use. 4 | 5 | try: 6 | import pyb 7 | _PYBOARD = True 8 | except ImportError: 9 | import machine 10 | _PYBOARD = False 11 | 12 | # Get a random number from 0-1 from a 2^24 bit random value 13 | # if run on the WiPy, return 0-1 from a 2^30 bit random 14 | # value if the Pyboard is used. 15 | def get_rand(): 16 | if _PYBOARD: 17 | return pyb.rng() / (2 ** 30 - 1) 18 | return machine.rng() / (2 ** 24 - 1) 19 | 20 | # Format the time (epoch) for a better view 21 | def format_time(tm_data): 22 | # Use a special shortcut to unpack tuple: *tm_data 23 | return "{0}-{1:0>2}-{2:0>2} {3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data) 24 | -------------------------------------------------------------------------------- /Source_Ch05/my_helper/sensor_convert.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example module for the my_helper library 3 | 4 | # This function converts values read from the sensor to a 5 | # string for use in qualifying the moisture level read. 6 | 7 | # Constants - adjust to "tune" your sensor 8 | 9 | _UPPER_BOUND = 400 10 | _LOWER_BOUND = 250 11 | 12 | def get_moisture_level(raw_value): 13 | if raw_value <= _LOWER_BOUND: 14 | return("dry") 15 | elif raw_value >= _UPPER_BOUND: 16 | return("wet") 17 | return("ok") 18 | 19 | 20 | -------------------------------------------------------------------------------- /Source_Ch05/my_vehicles.json: -------------------------------------------------------------------------------- 1 | {"color": "Pull me over red", "Make": "Chevrolet", "type": "pickup", "Model": "Silverado", "Year": 2015} 2 | -------------------------------------------------------------------------------- /Source_Ch05/sys_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of the sys library 3 | import sys 4 | print("Modules loaded: " , sys.modules) 5 | sys.path.append("/sd") 6 | print("Path: ", sys.path) 7 | sys.stdout.write("Platform: ") 8 | sys.stdout.write(sys.platform) 9 | sys.stdout.write("\n") 10 | sys.stdout.write("Version: ") 11 | sys.stdout.write(sys.version) 12 | sys.stdout.write("\n") 13 | sys.exit(1) 14 | -------------------------------------------------------------------------------- /Source_Ch05/uio_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of the uio library 3 | # Note: change uio to io to run this on your PC! 4 | import uio 5 | # Create the binary file 6 | fio_out = uio.FileIO('data.bin', 'wb') 7 | fio_out.write("\x5F\x9E\xAE\x09\x3E\x96\x68\x65\x6C\x6C\x6F") 8 | fio_out.write("\x00") 9 | fio_out.close() 10 | # Read the binary file and print out the results in hex and char. 11 | fio_in = uio.FileIO('data.bin', 'rb') 12 | print("Raw,Dec,Hex from file:") 13 | byte_val = fio_in.read(1) # read a byte 14 | while byte_val: 15 | print(byte_val, ",", ord(byte_val), hex(ord(byte_val))) 16 | byte_val = fio_in.read(1) # read a byte 17 | fio_in.close() 18 | 19 | -------------------------------------------------------------------------------- /Source_Ch05/ujson_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of the ujson library 3 | # Note: change ujson to json to run it on your PC! 4 | import ujson 5 | 6 | # Prepare a list of JSON documents for pets by converting JSON to a dictionary 7 | vehicles = [] 8 | vehicles.append(ujson.loads('{"make":"Chevrolet", "year":2015, "model":"Silverado", "color":"Pull me over red", "type":"pickup"}')) 9 | vehicles.append(ujson.loads('{"make":"Yamaha", "year":2009, "model":"R1", "color":"Blue/Silver", "type":"motorcycle"}')) 10 | vehicles.append(ujson.loads('{"make":"SeaDoo", "year":1997, "model":"Speedster", "color":"White", "type":"boat"}')) 11 | vehicles.append(ujson.loads('{"make":"TaoJen", "year":2013, "model":"Sicily", "color":"Black", "type":"Scooter"}')) 12 | 13 | # Now, write these entries to a file. Note: overwrites the file 14 | json_file = open("my_vehicles.json", "w") 15 | for vehicle in vehicles: 16 | json_file.write(ujson.dumps(vehicle)) 17 | json_file.write("\n") 18 | json_file.close() 19 | 20 | # Now, let's read the list of vehicles and print out their data 21 | my_vehicles = [] 22 | json_file = open("my_vehicles.json", "r") 23 | for vehicle in json_file.readlines(): 24 | parsed_json = ujson.loads(vehicle) 25 | my_vehicles.append(parsed_json) 26 | json_file.close() 27 | 28 | # Finally, print a summary of the vehicles 29 | print("Year Make Model Color") 30 | for vehicle in my_vehicles: 31 | print(vehicle['year'],vehicle['make'],vehicle['model'],vehicle['color']) 32 | 33 | -------------------------------------------------------------------------------- /Source_Ch05/uos_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of the uos library 3 | # Note: change uos to os to run it on your PC! 4 | import sys 5 | import uos 6 | 7 | # Create a method to display files in directory 8 | def show_files(): 9 | files = uos.listdir() 10 | sys.stdout.write("\nShow Files Output:\n") 11 | sys.stdout.write("\tname\tsize\n") 12 | for file in files: 13 | stats = uos.stat(file) 14 | # Print a directory with a "d" prefix and the size 15 | is_dir = True 16 | if stats[0] > 16384: 17 | is_dir = False 18 | if is_dir: 19 | sys.stdout.write("d\t") 20 | else: 21 | sys.stdout.write("\t") 22 | sys.stdout.write(file) 23 | if not is_dir: 24 | sys.stdout.write("\t") 25 | sys.stdout.write(str(stats[6])) 26 | sys.stdout.write("\n") 27 | 28 | # List the current directory 29 | show_files() 30 | # Change to the examples directory 31 | uos.chdir('examples') 32 | show_files() 33 | 34 | # Show how you can now use the import statement with the current dir 35 | print("\nRun the ujson_example with import ujson_example after chdir()") 36 | import ujson_example 37 | 38 | # Create a directory 39 | uos.mkdir("test") 40 | show_files() 41 | 42 | # Remove the directory 43 | uos.rmdir('test') 44 | show_files() 45 | -------------------------------------------------------------------------------- /Source_Ch05/utime_example.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example use of the utime library 3 | # Note: This example only works on the WiPy 4 | # Note: This example will not on your PC. 5 | import machine 6 | import sys 7 | import utime 8 | 9 | # Since we don't have a RTC, we have to set the current time 10 | # initialized the RTC in the WiPy machine library 11 | from machine import RTC 12 | 13 | # Init with default time and date 14 | rtc = RTC() 15 | # Init with a specific time and date. We use a specific 16 | # datetime, but we could get this from a network time 17 | # service. 18 | rtc = RTC(datetime=(2017, 7, 15, 21, 32, 11, 0, None)) 19 | 20 | # Get a random number from 0-1 from a 2^24 bit random value 21 | def get_rand(): 22 | return machine.rng() / (2 ** 24 - 1) 23 | 24 | # Format the time (epoch) for a better view 25 | def format_time(tm_data): 26 | # Use a special shortcut to unpack tuple: *tm_data 27 | return "{0}-{1:0>2}-{2:0>2} {3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data) 28 | 29 | # Generate a random number of rows from 0-25 30 | num_rows = get_rand() * 25 31 | 32 | # Print a row using random seconds, milleseconds, or microseconds 33 | # to simulate time. 34 | print("Datetime Value") 35 | print("------------------- --------") 36 | for i in range(0,num_rows): 37 | # Generate random value for our sensor 38 | value = get_rand() * 100 39 | # Wait a random number of seconds for time 40 | utime.sleep(int(get_rand() * 15)) # sleep up to 15 seconds 41 | print("{0} {1:0>{width}.4f}".format(format_time(rtc.now()), value, width=8)) 42 | 43 | 44 | -------------------------------------------------------------------------------- /Source_Ch05/wipy_ntp.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 5 2 | # Example module for using the ntptime server to set the datetime 3 | # Note: only works on WiPy! 4 | 5 | from network import WLAN 6 | from machine import RTC 7 | import machine 8 | import sys 9 | import utime 10 | 11 | wlan = WLAN(mode=WLAN.STA) 12 | 13 | def connect(): 14 | wifi_networks = wlan.scan() 15 | for wifi in wifi_networks: 16 | if wifi.ssid == "YOUR_SSID": 17 | wlan.connect(wifi.ssid, auth=(wifi.sec, "YOUR_SSID_PASSWORD"), timeout=5000) 18 | while not wlan.isconnected(): 19 | machine.idle() # save power while waiting 20 | print("Connected!") 21 | return True 22 | if not wlan.isconnected(): 23 | print("ERROR: Cannot connect! Exiting...") 24 | return False 25 | 26 | if not connect(): 27 | sys.exit(-1) 28 | 29 | # Now, setup the RTC with the NTP service. 30 | rtc = RTC() 31 | print("Time before sync:", rtc.now()) 32 | rtc.ntp_sync("pool.ntp.org") 33 | while not rtc.synced(): 34 | utime.sleep(1) 35 | print("waiting for NTP server...") 36 | print("Time after sync:", rtc.now()) 37 | 38 | -------------------------------------------------------------------------------- /Source_Ch06/pyboard_SPI.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Simple example for working with the SPI interface 3 | # using the Adafruit Thermocouple Amplifier. See 4 | # https://www.adafruit.com/product/269. 5 | # 6 | # Note: this only runs on the Pyboard 7 | # 8 | import machine 9 | import ubinascii 10 | 11 | # First, make sure this is running on a Pyboard 12 | try: 13 | import pyb 14 | from pyb import SPI 15 | except ImportError: 16 | print("ERROR: not on a Pyboard!") 17 | sys.exit(-1) 18 | 19 | # Create a method to normalize the data into degrees Celsius 20 | def normalize_data(data): 21 | temp = data[0] << 8 | data[1] 22 | if temp & 0x0001: 23 | return float('NaN') 24 | temp >>= 2 25 | if temp & 0x2000: 26 | temp -= 16384 27 | return (temp * 0.25) 28 | 29 | # Setup the SPI interfaceon the "Y" interface 30 | spi = SPI(2, SPI.MASTER, baudrate=5000000, polarity=0, phase=0) 31 | cs = machine.Pin("Y5", machine.Pin.OUT) 32 | cs.high() 33 | 34 | # read from the chip 35 | print("Reading temperature every second.") 36 | print("Press CTRL-C to stop.") 37 | while True: 38 | pyb.delay(1000) 39 | cs.low() 40 | print("Temperature is {0} Celsius.".format(normalize_data(spi.recv(4)))) 41 | cs.high() 42 | 43 | 44 | -------------------------------------------------------------------------------- /Source_Ch06/pyboard_accel.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Example for working with the accelerometer on a Pyboard 3 | # Note: only works for the Pyboard! 4 | 5 | import pyb 6 | from pyb import Accel 7 | acc = Accel() 8 | print("Press CTRL-C to stop.") 9 | while True: 10 | pyb.delay(500) # Short delay before sampling 11 | print("X = {0:03} Y = {1:03} Z = {2:03}".format(acc.x(), acc.y(), acc.z())) 12 | -------------------------------------------------------------------------------- /Source_Ch06/pyboard_button.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Simple example for working with interrupts using a class 3 | # to store state. 4 | # 5 | import sys 6 | 7 | # First, make sure this is running on a Pyboard 8 | try: 9 | import pyb 10 | except ImportError: 11 | print("ERROR: not on a Pyboard!") 12 | sys.exit(-1) 13 | 14 | # Initiate the switch class 15 | switch = pyb.Switch() 16 | 17 | class Cycle_LED(object): 18 | # Constructor 19 | def __init__(self, sw): 20 | self.cur_led = 0 21 | sw.callback(self.do_switch_press) 22 | 23 | # Switch callback function 24 | def do_switch_press(self):# 25 | # Turn off the last led unless this is the first time through the cycle 26 | if self.cur_led > 0: 27 | pyb.LED(self.cur_led).off() 28 | if self.cur_led < 4: 29 | self.cur_led = self.cur_led + 1 30 | else: 31 | self.cur_led = 1 32 | # Turn on the next led 33 | pyb.LED(self.cur_led).on() 34 | 35 | # Initiate the Cycle_LED class and setup the callback 36 | cycle = Cycle_LED(switch) 37 | 38 | # Now, simulate doing something else 39 | print("Testing the switch callback. Press CTRL-C to quit.") 40 | while True: 41 | sys.stdout.write(".") # Print something to show we're still in the loop 42 | pyb.delay(1000) # Wait a second... 43 | 44 | -------------------------------------------------------------------------------- /Source_Ch06/pyboard_lcd.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Example module for the LCD skin on a Pyboard 3 | # 4 | # Note: The LCD is positioned in the "X" position. 5 | # 6 | import sys 7 | 8 | # First, make sure this is running on a Pyboard 9 | try: 10 | import pyb 11 | except ImportError: 12 | print("ERROR: not on a Pyboard!") 13 | sys.exit(-1) 14 | 15 | # Next, make sure the LCD skin library in the firmware 16 | try: 17 | import lcd160cr 18 | except ImportError: 19 | print("ERROR: LCD160CR library missing!") 20 | sys.exit(-1) 21 | 22 | # Return color of LED 23 | def led_color(num): 24 | if num == 1: return "red" 25 | elif num == 2: return "green" 26 | elif num == 3: return "orange" 27 | else: return "blue" 28 | 29 | # Use a method to turn off last LED and the next one on 30 | def turn_on_led(num, led_last): 31 | # turn last LED off 32 | led = pyb.LED(led_last) 33 | led.off() 34 | led = pyb.LED(num) 35 | led.on() 36 | sys.stdout.write("Turning off ") 37 | sys.stdout.write(led_color(led_last)) 38 | sys.stdout.write(" - Turning on ") 39 | sys.stdout.write(led_color(num)) 40 | sys.stdout.write("\n") 41 | 42 | # Setup the LCD in the "X" position 43 | lcd = lcd160cr.LCD160CR('X') 44 | 45 | for j in range(1, 4): # Turn off all of the LEDs 46 | led = pyb.LED(j) # Get the LED 47 | led.off() # Turn the LED off 48 | 49 | # Now, let's play a game. Let's change the LEDs to 50 | # different colors depending on where the user touches 51 | # the screen. 52 | print("Welcome to the touch screen demo!") 53 | print("Touch the screen in the corners to change the LED lit.") 54 | print("Touch the center to exit.") 55 | center = False 56 | last_led = 1 57 | while not center: 58 | pyb.delay(50) 59 | if lcd.is_touched: 60 | touch = lcd.get_touch() 61 | if (touch[0] == 0): 62 | continue 63 | # Upper-left corner 64 | if ((touch[1] <= 60) and (touch[2] <= 60)): 65 | turn_on_led(1, last_led) 66 | last_led = 1 67 | # Upper-right corner 68 | elif ((touch[1] >= 100) and (touch[2] <= 60)): 69 | turn_on_led(2, last_led) 70 | last_led = 2 71 | # Lower-right corner 72 | elif ((touch[1] >= 100) and (touch[2] >= 100)): 73 | turn_on_led(3, last_led) 74 | last_led = 3 75 | # Lower-left corner 76 | elif ((touch[1] <= 60) and (touch[2] >= 100)): 77 | turn_on_led(4, last_led) 78 | last_led = 4 79 | # Center 80 | elif ((touch[1] > 60) and (touch[1] < 100) and (touch[2] > 60) and (touch[2] < 100)): 81 | led = pyb.LED(last_led) 82 | led.off() 83 | center = True 84 | 85 | print("Thanks for playing!") 86 | sys.exit(0) 87 | -------------------------------------------------------------------------------- /Source_Ch06/secret_log.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/micropython-for-internet-of-things/c769013c4ea965375bda1964efdbede8489d4a1f/Source_Ch06/secret_log.txt -------------------------------------------------------------------------------- /Source_Ch06/wipy_RGB.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Example of using the I2C interface via a driver 3 | # for the Adafruit RGB Sensor tcs34725 4 | # 5 | # Requires library: 6 | # https://github.com/adafruit/micropython-adafruit-tcs34725 7 | # 8 | from machine import I2C, Pin 9 | import sys 10 | import tcs34725 11 | import utime 12 | 13 | # Method to read sensor and display results 14 | def read_sensor(rgb_sense, led): 15 | sys.stdout.write("Place object in front of sensor now...") 16 | led.value(1) # Turn on the LED 17 | utime.sleep(5) # Wait 5 seconds 18 | data = rgb_sense.read(True) # Get the RGBC values 19 | print("color detected: {") 20 | print(" Red: {0:03}".format(data[0])) 21 | print(" Green: {0:03}".format(data[1])) 22 | print(" Blue: {0:03}".format(data[2])) 23 | print(" Clear: {0:03}".format(data[3])) 24 | print("}") 25 | led.value(0) 26 | 27 | # Setup the I2C - easy, yes? 28 | i2c = I2C(0, I2C.MASTER) # create and init as a master 29 | i2c.init(I2C.MASTER, baudrate=20000) # init as a master 30 | i2c.scan() 31 | 32 | # Setup the sensor 33 | sensor = tcs34725.TCS34725(i2c) 34 | 35 | # Setup the LED pin 36 | led_pin = Pin("P8", Pin.OUT) 37 | led_pin.value(0) 38 | 39 | print("Reading Colors every 10 seconds. When LED is on, place object in front of sensor.") 40 | print("Press CTRL-C to quit. (wait for it)") 41 | while True: 42 | utime.sleep(10) # Sleep for 10 seconds 43 | read_sensor(sensor, led_pin) # Read sensor and display values 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Source_Ch06/wipy_encryption.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Simple example for working with encrypting data 3 | # 4 | import sys 5 | 6 | # First, make sure this is running on a WiPy (pycom) 7 | try: 8 | import pycom 9 | from crypto import AES 10 | except ImportError: 11 | print("ERROR: not on a WiPy (or Pycom) board!") 12 | sys.exit(-1) 13 | 14 | # Setup encryption using simple, basic encryption 15 | # NOTICE: you normally would protect this key! 16 | my_key = b'monkeybreadyummy' # 128 bit (16 bytes) key 17 | cipher = AES(my_key, AES.MODE_ECB) 18 | 19 | # Create the file and encrypt the data 20 | new_file = open("secret_log.txt", "w") # use "write" mode 21 | new_file.write(cipher.encrypt("1,apples,2.5 \n")) # write some data 22 | new_file.write(cipher.encrypt("2,oranges,1 \n")) # write some data 23 | new_file.write(cipher.encrypt("3,peaches,3 \n")) # write some data 24 | new_file.write(cipher.encrypt("4,grapes,21 \n")) # write some data 25 | new_file.close() # close the file 26 | 27 | # Step 2: Open the file and read data 28 | old_file = open("secret_log.txt", "r") # use "read" mode 29 | # Use a loop to read all rows in the file 30 | for row in old_file.readlines(): 31 | data = cipher.decrypt(row).decode('ascii') 32 | columns = data.strip("\n").split(",") # split row by commas 33 | print(" : ".join(columns)) # print the row with colon separator 34 | 35 | old_file.close() 36 | -------------------------------------------------------------------------------- /Source_Ch06/wipy_heartbeat.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 6 2 | # Example for working with the hearbeat LED as a 3 | # status/state indicator 4 | # 5 | import utime 6 | 7 | # First, make sure this is running on a Pyboard 8 | try: 9 | import pycom 10 | except ImportError: 11 | print("ERROR: not on a WiPy (or Pycom) board!") 12 | sys.exit(-1) 13 | 14 | # State/status enumeration 15 | _STATES = { 16 | 'ERROR' : 0xFF0000, # Bright red 17 | 'READING' : 0x00FF00, # Green 18 | 'WRITING' : 0x0000FF, # Blue 19 | 'OK' : 0xFF33FF, # Pinkish 20 | } 21 | 22 | # Clear the state (return to normal operation) 23 | def clear_status(): 24 | pycom.heartbeat(True) 25 | 26 | # Show state/status with the heatbeat LED 27 | def show_status(state): 28 | pycom.heartbeat(False) 29 | pycom.rgbled(state) 30 | 31 | # Now, demonstrate the state changes 32 | for state in _STATES.keys(): 33 | show_status(_STATES[state]) 34 | utime.sleep(3) 35 | 36 | # Return heartbeat to normal 37 | clear_status() 38 | -------------------------------------------------------------------------------- /Source_Ch08/Pyboard/clock.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 8 2 | # 3 | # Project 1: A MicroPython Clock! 4 | # 5 | # Required Components: 6 | # - Pyboard 7 | # - OLED SPI display 8 | # - RTC I2C module 9 | # 10 | # Note: this only runs on the Pyboard. See chapter text 11 | # for how to modify this to run on the WiPy. 12 | # 13 | 14 | # Imports for the project 15 | import pyb 16 | import urtc 17 | from machine import SPI, Pin as pin 18 | from pyb import I2C 19 | from ssd1306 import SSD1306_SPI as ssd 20 | 21 | # Setup SPI and I2C 22 | spi = SPI(2, baudrate=8000000, polarity=0, phase=0) 23 | i2c = I2C(1, I2C.MASTER) 24 | i2c.init(I2C.MASTER, baudrate=500000) 25 | 26 | # Setup the OLED : D/C, RST, CS 27 | oled_module = ssd(128,32,spi,pin("Y4"),pin("Y3"),pin("Y5")) 28 | 29 | # Setup the RTC 30 | rtc_module = urtc.DS1307(i2c) 31 | # 32 | # NOTE: We only need to set the datetime once. Uncomment these 33 | # lines only on the first run of a new RTC module or 34 | # whenever you change the battery. 35 | # (year, month, day, weekday, hour, minute, second, millisecond) 36 | #start_datetime = (2017,07,20,4,9,0,0,0) 37 | #rtc_module.datetime(start_datetime) 38 | 39 | # Return a string to print the day of the week 40 | def get_weekday(day): 41 | if day == 1: return "Sunday" 42 | elif day == 2: return "Monday" 43 | elif day == 3: return "Tuesday" 44 | elif day == 4: return "Wednesday" 45 | elif day == 5: return "Thursday" 46 | elif day == 6: return "Friday" 47 | else: return "Saturday" 48 | 49 | # Display the date and time 50 | def write_time(oled, rtc): 51 | # Get datetime 52 | dt = rtc.datetime() 53 | # Print the date 54 | oled.text("Date: {0:02}/{1:02}/{2:04}".format(dt[1], dt[2], dt[0]), 0, 0) 55 | # Print the time 56 | oled.text("Time: {0:02}:{1:02}:{2:02}".format(dt[4], dt[5], dt[6]), 0, 10) 57 | # Print the day of the week 58 | oled.text("Day: {0}".format(get_weekday(dt[3])), 0, 20) 59 | # Update the OLED 60 | oled.show() 61 | 62 | # Clear the screen 63 | def clear_screen(oled): 64 | oled.fill(0) 65 | oled.show() 66 | 67 | # Here, we make a "run" function to be used from the main.py 68 | # code module. This is preferable to direct "main" execution. 69 | def run(): 70 | # Display the deate and time every second 71 | while True: 72 | clear_screen(oled_module) 73 | write_time(oled_module, rtc_module) 74 | pyb.delay(1000) 75 | -------------------------------------------------------------------------------- /Source_Ch08/Pyboard/main.py: -------------------------------------------------------------------------------- 1 | # main.py -- put your code here! 2 | import clock 3 | clock.run() 4 | -------------------------------------------------------------------------------- /Source_Ch08/Pyboard/ssd1306.py: -------------------------------------------------------------------------------- 1 | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces 2 | 3 | import time 4 | import framebuf 5 | 6 | 7 | # register definitions 8 | SET_CONTRAST = const(0x81) 9 | SET_ENTIRE_ON = const(0xa4) 10 | SET_NORM_INV = const(0xa6) 11 | SET_DISP = const(0xae) 12 | SET_MEM_ADDR = const(0x20) 13 | SET_COL_ADDR = const(0x21) 14 | SET_PAGE_ADDR = const(0x22) 15 | SET_DISP_START_LINE = const(0x40) 16 | SET_SEG_REMAP = const(0xa0) 17 | SET_MUX_RATIO = const(0xa8) 18 | SET_COM_OUT_DIR = const(0xc0) 19 | SET_DISP_OFFSET = const(0xd3) 20 | SET_COM_PIN_CFG = const(0xda) 21 | SET_DISP_CLK_DIV = const(0xd5) 22 | SET_PRECHARGE = const(0xd9) 23 | SET_VCOM_DESEL = const(0xdb) 24 | SET_CHARGE_PUMP = const(0x8d) 25 | 26 | 27 | class SSD1306: 28 | def __init__(self, width, height, external_vcc): 29 | self.width = width 30 | self.height = height 31 | self.external_vcc = external_vcc 32 | self.pages = self.height // 8 33 | # Note the subclass must initialize self.framebuf to a framebuffer. 34 | # This is necessary because the underlying data buffer is different 35 | # between I2C and SPI implementations (I2C needs an extra byte). 36 | self.poweron() 37 | self.init_display() 38 | 39 | def init_display(self): 40 | for cmd in ( 41 | SET_DISP | 0x00, # off 42 | # address setting 43 | SET_MEM_ADDR, 0x00, # horizontal 44 | # resolution and layout 45 | SET_DISP_START_LINE | 0x00, 46 | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 47 | SET_MUX_RATIO, self.height - 1, 48 | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 49 | SET_DISP_OFFSET, 0x00, 50 | SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, 51 | # timing and driving scheme 52 | SET_DISP_CLK_DIV, 0x80, 53 | SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, 54 | SET_VCOM_DESEL, 0x30, # 0.83*Vcc 55 | # display 56 | SET_CONTRAST, 0xff, # maximum 57 | SET_ENTIRE_ON, # output follows RAM contents 58 | SET_NORM_INV, # not inverted 59 | # charge pump 60 | SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, 61 | SET_DISP | 0x01): # on 62 | self.write_cmd(cmd) 63 | self.fill(0) 64 | self.show() 65 | 66 | def poweroff(self): 67 | self.write_cmd(SET_DISP | 0x00) 68 | 69 | def contrast(self, contrast): 70 | self.write_cmd(SET_CONTRAST) 71 | self.write_cmd(contrast) 72 | 73 | def invert(self, invert): 74 | self.write_cmd(SET_NORM_INV | (invert & 1)) 75 | 76 | def show(self): 77 | x0 = 0 78 | x1 = self.width - 1 79 | if self.width == 64: 80 | # displays with width of 64 pixels are shifted by 32 81 | x0 += 32 82 | x1 += 32 83 | self.write_cmd(SET_COL_ADDR) 84 | self.write_cmd(x0) 85 | self.write_cmd(x1) 86 | self.write_cmd(SET_PAGE_ADDR) 87 | self.write_cmd(0) 88 | self.write_cmd(self.pages - 1) 89 | self.write_framebuf() 90 | 91 | def fill(self, col): 92 | self.framebuf.fill(col) 93 | 94 | def pixel(self, x, y, col): 95 | self.framebuf.pixel(x, y, col) 96 | 97 | def scroll(self, dx, dy): 98 | self.framebuf.scroll(dx, dy) 99 | 100 | def text(self, string, x, y, col=1): 101 | self.framebuf.text(string, x, y, col) 102 | 103 | 104 | class SSD1306_I2C(SSD1306): 105 | def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): 106 | self.i2c = i2c 107 | self.addr = addr 108 | self.temp = bytearray(2) 109 | # Add an extra byte to the data buffer to hold an I2C data/command byte 110 | # to use hardware-compatible I2C transactions. A memoryview of the 111 | # buffer is used to mask this byte from the framebuffer operations 112 | # (without a major memory hit as memoryview doesn't copy to a separate 113 | # buffer). 114 | self.buffer = bytearray(((height // 8) * width) + 1) 115 | self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1 116 | self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height) 117 | super().__init__(width, height, external_vcc) 118 | 119 | def write_cmd(self, cmd): 120 | self.temp[0] = 0x80 # Co=1, D/C#=0 121 | self.temp[1] = cmd 122 | self.i2c.writeto(self.addr, self.temp) 123 | 124 | def write_framebuf(self): 125 | # Blast out the frame buffer using a single I2C transaction to support 126 | # hardware I2C interfaces. 127 | self.i2c.writeto(self.addr, self.buffer) 128 | 129 | def poweron(self): 130 | pass 131 | 132 | 133 | class SSD1306_SPI(SSD1306): 134 | def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): 135 | self.rate = 10 * 1024 * 1024 136 | dc.init(dc.OUT, value=0) 137 | res.init(res.OUT, value=0) 138 | cs.init(cs.OUT, value=1) 139 | self.spi = spi 140 | self.dc = dc 141 | self.res = res 142 | self.cs = cs 143 | self.buffer = bytearray((height // 8) * width) 144 | self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height) 145 | super().__init__(width, height, external_vcc) 146 | 147 | def write_cmd(self, cmd): 148 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 149 | self.cs.high() 150 | self.dc.low() 151 | self.cs.low() 152 | self.spi.write(bytearray([cmd])) 153 | self.cs.high() 154 | 155 | def write_framebuf(self): 156 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 157 | self.cs.high() 158 | self.dc.high() 159 | self.cs.low() 160 | self.spi.write(self.buffer) 161 | self.cs.high() 162 | 163 | def poweron(self): 164 | self.res.high() 165 | time.sleep_ms(1) 166 | self.res.low() 167 | time.sleep_ms(10) 168 | self.res.high() 169 | -------------------------------------------------------------------------------- /Source_Ch08/Pyboard/urtc.py: -------------------------------------------------------------------------------- 1 | import ucollections 2 | import utime 3 | 4 | 5 | DateTimeTuple = ucollections.namedtuple("DateTimeTuple", ["year", "month", 6 | "day", "weekday", "hour", "minute", "second", "millisecond"]) 7 | 8 | 9 | def datetime_tuple(year=None, month=None, day=None, weekday=None, hour=None, 10 | minute=None, second=None, millisecond=None): 11 | return DateTimeTuple(year, month, day, weekday, hour, minute, 12 | second, millisecond) 13 | 14 | 15 | def _bcd2bin(value): 16 | return (value or 0) - 6 * ((value or 0) >> 4) 17 | 18 | 19 | def _bin2bcd(value): 20 | return (value or 0) + 6 * ((value or 0) // 10) 21 | 22 | 23 | def tuple2seconds(datetime): 24 | return utime.mktime((datetime.year, datetime.month, datetime.day, 25 | datetime.hour, datetime.minute, datetime.second, datetime.weekday, 0)) 26 | 27 | 28 | def seconds2tuple(seconds): 29 | (year, month, day, hour, minute, 30 | second, weekday, _yday) = utime.localtime(seconds) 31 | return DateTimeTuple(year, month, day, weekday, hour, minute, second, 0) 32 | 33 | 34 | class _BaseRTC: 35 | _SWAP_DAY_WEEKDAY = False 36 | 37 | def __init__(self, i2c, address=0x68): 38 | self.i2c = i2c 39 | self.address = address 40 | 41 | def _register(self, register, buffer=None): 42 | if buffer is None: 43 | return self.i2c.mem_read(1, self.address, register)[0] 44 | self.i2c.mem_write(buffer, self.address, register) 45 | 46 | def _flag(self, register, mask, value=None): 47 | data = self._register(register) 48 | if value is None: 49 | return bool(data & mask) 50 | if value: 51 | data |= mask 52 | else: 53 | data &= ~mask 54 | self._register(register, bytearray((data,))) 55 | 56 | 57 | def datetime(self, datetime=None): 58 | if datetime is None: 59 | buffer = self.i2c.mem_read(7, self.address, 60 | self._DATETIME_REGISTER) 61 | if self._SWAP_DAY_WEEKDAY: 62 | day = buffer[3] 63 | weekday = buffer[4] 64 | else: 65 | day = buffer[4] 66 | weekday = buffer[3] 67 | return datetime_tuple( 68 | year=_bcd2bin(buffer[6]) + 2000, 69 | month=_bcd2bin(buffer[5]), 70 | day=_bcd2bin(day), 71 | weekday=_bcd2bin(weekday), 72 | hour=_bcd2bin(buffer[2]), 73 | minute=_bcd2bin(buffer[1]), 74 | second=_bcd2bin(buffer[0]), 75 | ) 76 | datetime = datetime_tuple(*datetime) 77 | buffer = bytearray(7) 78 | buffer[0] = _bin2bcd(datetime.second) 79 | buffer[1] = _bin2bcd(datetime.minute) 80 | buffer[2] = _bin2bcd(datetime.hour) 81 | if self._SWAP_DAY_WEEKDAY: 82 | buffer[4] = _bin2bcd(datetime.weekday) 83 | buffer[3] = _bin2bcd(datetime.day) 84 | else: 85 | buffer[3] = _bin2bcd(datetime.weekday) 86 | buffer[4] = _bin2bcd(datetime.day) 87 | buffer[5] = _bin2bcd(datetime.month) 88 | buffer[6] = _bin2bcd(datetime.year - 2000) 89 | self._register(self._DATETIME_REGISTER, buffer) 90 | 91 | 92 | class DS1307(_BaseRTC): 93 | _NVRAM_REGISTER = 0x08 94 | _DATETIME_REGISTER = 0x00 95 | _SQUARE_WAVE_REGISTER = 0x07 96 | 97 | def stop(self, value=None): 98 | return self._flag(0x00, 0b10000000, value) 99 | 100 | def memory(self, address, buffer=None): 101 | if buffer is not None and address + len(buffer) > 56: 102 | raise ValueError("address out of range") 103 | return self._register(self._NVRAM_REGISTER + address, buffer) 104 | 105 | 106 | class DS3231(_BaseRTC): 107 | _CONTROL_REGISTER = 0x0e 108 | _STATUS_REGISTER = 0x0f 109 | _DATETIME_REGISTER = 0x00 110 | _ALARM_REGISTERS = (0x08, 0x0b) 111 | _SQUARE_WAVE_REGISTER = 0x0e 112 | 113 | def lost_power(self): 114 | return self._flag(self._STATUS_REGISTER, 0b10000000) 115 | 116 | def alarm(self, value=None, alarm=0): 117 | return self._flag(self._STATUS_REGISTER, 118 | 0b00000011 & (1 << alarm), value) 119 | 120 | def stop(self, value=None): 121 | return self._flag(self._CONTROL_REGISTER, 0b10000000, value) 122 | 123 | def datetime(self, datetime=None): 124 | if datetime is not None: 125 | status = self._register(self._STATUS_REGISTER) & 0b01111111 126 | self._register(self._STATUS_REGISTER, bytearray((status,))) 127 | return super().datetime(datetime) 128 | 129 | def alarm_time(self, datetime=None, alarm=0): 130 | if datetime is None: 131 | buffer = self.i2c.mem_read(3, self.address, 132 | self._ALARM_REGISTERS[alarm]) 133 | day = None 134 | weekday = None 135 | second = None 136 | if buffer[2] & 0b10000000: 137 | pass 138 | elif buffer[2] & 0b01000000: 139 | day = _bcd2bin(buffer[2] & 0x3f) 140 | else: 141 | weekday = _bcd2bin(buffer[2] & 0x3f) 142 | minute = (_bcd2bin(buffer[0] & 0x7f) 143 | if not buffer[0] & 0x80 else None) 144 | hour = (_bcd2bin(buffer[1] & 0x7f) 145 | if not buffer[1] & 0x80 else None) 146 | if alarm == 0: 147 | # handle seconds 148 | buffer = self.i2c.mem_read(1, 149 | self.address, self._ALARM_REGISTERS[alarm] - 1) 150 | second = (_bcd2bin(buffer[0] & 0x7f) 151 | if not buffer[0] & 0x80 else None) 152 | return datetime_tuple( 153 | day=day, 154 | weekday=weekday, 155 | hour=hour, 156 | minute=minute, 157 | second=second, 158 | ) 159 | datetime = datetime_tuple(*datetime) 160 | buffer = bytearray(3) 161 | buffer[0] = (_bin2bcd(datetime.minute) 162 | if datetime.minute is not None else 0x80) 163 | buffer[1] = (_bin2bcd(datetime.hour) 164 | if datetime.hour is not None else 0x80) 165 | if datetime.day is not None: 166 | if datetime.weekday is not None: 167 | raise ValueError("can't specify both day and weekday") 168 | buffer[2] = _bin2bcd(datetime.day) | 0b01000000 169 | elif datetime.weekday is not None: 170 | buffer[2] = _bin2bcd(datetime.weekday) 171 | else: 172 | buffer[2] = 0x80 173 | self._register(self._ALARM_REGISTERS[alarm], buffer) 174 | if alarm == 0: 175 | # handle seconds 176 | buffer = bytearray([_bin2bcd(datetime.second) 177 | if datetime.second is not None else 0x80]) 178 | self._register(self._ALARM_REGISTERS[alarm] - 1, buffer) 179 | 180 | 181 | 182 | class PCF8523(_BaseRTC): 183 | _CONTROL1_REGISTER = 0x00 184 | _CONTROL2_REGISTER = 0x01 185 | _CONTROL3_REGISTER = 0x02 186 | _DATETIME_REGISTER = 0x03 187 | _ALARM_REGISTER = 0x0a 188 | _SQUARE_WAVE_REGISTER = 0x0f 189 | _SWAP_DAY_WEEKDAY = True 190 | 191 | def __init__(self, *args, **kwargs): 192 | super().__init__(*args, **kwargs) 193 | self.init() 194 | 195 | def init(self): 196 | # Enable battery switchover and low-battery detection. 197 | self._flag(self._CONTROL3_REGISTER, 0b11100000, False) 198 | 199 | def reset(self): 200 | self._flag(self._CONTROL1_REGISTER, 0x58, True) 201 | self.init() 202 | 203 | def lost_power(self, value=None): 204 | return self._flag(self._CONTROL3_REGISTER, 0b00010000, value) 205 | 206 | def stop(self, value=None): 207 | return self._flag(self._CONTROL1_REGISTER, 0b00010000, value) 208 | 209 | def battery_low(self): 210 | return self._flag(self._CONTROL3_REGISTER, 0b00000100) 211 | 212 | def alarm(self, value=None): 213 | return self._flag(self._CONTROL2_REGISTER, 0b00001000, value) 214 | 215 | def datetime(self, datetime=None): 216 | if datetime is not None: 217 | self.lost_power(False) # clear the battery switchover flag 218 | return super().datetime(datetime) 219 | 220 | def alarm_time(self, datetime=None): 221 | if datetime is None: 222 | buffer = self.i2c.mem_read(4, self.address, 223 | self._ALARM_REGISTER) 224 | return datetime_tuple( 225 | weekday=_bcd2bin(buffer[3] & 226 | 0x7f) if not buffer[3] & 0x80 else None, 227 | day=_bcd2bin(buffer[2] & 228 | 0x7f) if not buffer[2] & 0x80 else None, 229 | hour=_bcd2bin(buffer[1] & 230 | 0x7f) if not buffer[1] & 0x80 else None, 231 | minute=_bcd2bin(buffer[0] & 232 | 0x7f) if not buffer[0] & 0x80 else None, 233 | ) 234 | datetime = datetime_tuple(*datetime) 235 | buffer = bytearray(4) 236 | buffer[0] = (_bin2bcd(datetime.minute) 237 | if datetime.minute is not None else 0x80) 238 | buffer[1] = (_bin2bcd(datetime.hour) 239 | if datetime.hour is not None else 0x80) 240 | buffer[2] = (_bin2bcd(datetime.day) 241 | if datetime.day is not None else 0x80) 242 | buffer[3] = (_bin2bcd(datetime.weekday) | 0b01000000 243 | if datetime.weekday is not None else 0x80) 244 | self._register(self._ALARM_REGISTER, buffer) 245 | -------------------------------------------------------------------------------- /Source_Ch08/WiPy/clock.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 8 2 | # 3 | # Project 1: A MicroPython Clock! 4 | # 5 | # Required Components: 6 | # - Pyboard 7 | # - OLED SPI display 8 | # - RTC I2C module 9 | # 10 | # Note: this only runs on the WiPy. See chapter text 11 | # for how to modify this to run on the Pyboard. 12 | # 13 | 14 | # Imports for the project 15 | import urtc 16 | import utime 17 | from machine import SPI, I2C, RTC as rtc, Pin as pin 18 | from ssd1306 import SSD1306_SPI as ssd 19 | 20 | # Setup SPI and I2C 21 | spi = SPI(0, SPI.MASTER, baudrate=2000000, polarity=0, phase=0) 22 | i2c = I2C(0, I2C.MASTER, baudrate=100000,pins=("P9", "P8")) 23 | 24 | # Setup the OLED : D/C, RST, CS 25 | oled_module = ssd(128,32,spi,pin('P5'),pin('P6'),pin('P7')) 26 | 27 | # Setup the RTC 28 | rtc_module = urtc.DS1307(i2c) 29 | # 30 | # NOTE: We only need to set the datetime once. Uncomment these 31 | # lines only on the first run of a new RTC module or 32 | # whenever you change the battery. 33 | # (year, month, day, weekday, hour, minute, second, millisecond) 34 | #start_datetime = (2017,07,20,4,9,0,0,0) 35 | #rtc_module.datetime(start_datetime) 36 | 37 | # Return a string to print the day of the week 38 | def get_weekday(day): 39 | if day == 1: return "Sunday" 40 | elif day == 2: return "Monday" 41 | elif day == 3: return "Tuesday" 42 | elif day == 4: return "Wednesday" 43 | elif day == 5: return "Thursday" 44 | elif day == 6: return "Friday" 45 | else: return "Saturday" 46 | 47 | # Display the date and time 48 | def write_time(oled, rtc): 49 | # Get datetime 50 | dt = rtc.datetime() 51 | # Print the date 52 | oled.text("Date: {0:02}/{1:02}/{2:04}".format(dt[1], dt[2], dt[0]), 0, 0) 53 | # Print the time 54 | oled.text("Time: {0:02}:{1:02}:{2:02}".format(dt[4], dt[5], dt[6]), 0, 10) 55 | # Print the day of the week 56 | oled.text("Day: {0}".format(get_weekday(dt[3])), 0, 20) 57 | # Update the OLED 58 | oled.show() 59 | 60 | # Clear the screen 61 | def clear_screen(oled): 62 | oled.fill(0) 63 | oled.show() 64 | 65 | # Here, we make a "run" function to be used from the main.py 66 | # code module. This is preferable to direct "main" execution. 67 | def run(): 68 | # Display the deate and time every second 69 | while True: 70 | clear_screen(oled_module) 71 | write_time(oled_module, rtc_module) 72 | utime.sleep(1) 73 | -------------------------------------------------------------------------------- /Source_Ch08/WiPy/main.py: -------------------------------------------------------------------------------- 1 | # main.py -- put your code here! 2 | import clock 3 | clock.run() 4 | -------------------------------------------------------------------------------- /Source_Ch08/WiPy/ssd1306.py: -------------------------------------------------------------------------------- 1 | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces 2 | 3 | import time 4 | import framebuf 5 | 6 | 7 | # register definitions 8 | SET_CONTRAST = const(0x81) 9 | SET_ENTIRE_ON = const(0xa4) 10 | SET_NORM_INV = const(0xa6) 11 | SET_DISP = const(0xae) 12 | SET_MEM_ADDR = const(0x20) 13 | SET_COL_ADDR = const(0x21) 14 | SET_PAGE_ADDR = const(0x22) 15 | SET_DISP_START_LINE = const(0x40) 16 | SET_SEG_REMAP = const(0xa0) 17 | SET_MUX_RATIO = const(0xa8) 18 | SET_COM_OUT_DIR = const(0xc0) 19 | SET_DISP_OFFSET = const(0xd3) 20 | SET_COM_PIN_CFG = const(0xda) 21 | SET_DISP_CLK_DIV = const(0xd5) 22 | SET_PRECHARGE = const(0xd9) 23 | SET_VCOM_DESEL = const(0xdb) 24 | SET_CHARGE_PUMP = const(0x8d) 25 | 26 | 27 | class SSD1306: 28 | def __init__(self, width, height, external_vcc): 29 | self.width = width 30 | self.height = height 31 | self.external_vcc = external_vcc 32 | self.pages = self.height // 8 33 | # Note the subclass must initialize self.framebuf to a framebuffer. 34 | # This is necessary because the underlying data buffer is different 35 | # between I2C and SPI implementations (I2C needs an extra byte). 36 | self.poweron() 37 | self.init_display() 38 | 39 | def init_display(self): 40 | for cmd in ( 41 | SET_DISP | 0x00, # off 42 | # address setting 43 | SET_MEM_ADDR, 0x00, # horizontal 44 | # resolution and layout 45 | SET_DISP_START_LINE | 0x00, 46 | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 47 | SET_MUX_RATIO, self.height - 1, 48 | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 49 | SET_DISP_OFFSET, 0x00, 50 | SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, 51 | # timing and driving scheme 52 | SET_DISP_CLK_DIV, 0x80, 53 | SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, 54 | SET_VCOM_DESEL, 0x30, # 0.83*Vcc 55 | # display 56 | SET_CONTRAST, 0xff, # maximum 57 | SET_ENTIRE_ON, # output follows RAM contents 58 | SET_NORM_INV, # not inverted 59 | # charge pump 60 | SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, 61 | SET_DISP | 0x01): # on 62 | self.write_cmd(cmd) 63 | self.fill(0) 64 | self.show() 65 | 66 | def poweroff(self): 67 | self.write_cmd(SET_DISP | 0x00) 68 | 69 | def contrast(self, contrast): 70 | self.write_cmd(SET_CONTRAST) 71 | self.write_cmd(contrast) 72 | 73 | def invert(self, invert): 74 | self.write_cmd(SET_NORM_INV | (invert & 1)) 75 | 76 | def show(self): 77 | x0 = 0 78 | x1 = self.width - 1 79 | if self.width == 64: 80 | # displays with width of 64 pixels are shifted by 32 81 | x0 += 32 82 | x1 += 32 83 | self.write_cmd(SET_COL_ADDR) 84 | self.write_cmd(x0) 85 | self.write_cmd(x1) 86 | self.write_cmd(SET_PAGE_ADDR) 87 | self.write_cmd(0) 88 | self.write_cmd(self.pages - 1) 89 | self.write_framebuf() 90 | 91 | def fill(self, col): 92 | self.framebuf.fill(col) 93 | 94 | def pixel(self, x, y, col): 95 | self.framebuf.pixel(x, y, col) 96 | 97 | def scroll(self, dx, dy): 98 | self.framebuf.scroll(dx, dy) 99 | 100 | def text(self, string, x, y, col=1): 101 | self.framebuf.text(string, x, y, col) 102 | 103 | 104 | class SSD1306_I2C(SSD1306): 105 | def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): 106 | self.i2c = i2c 107 | self.addr = addr 108 | self.temp = bytearray(2) 109 | # Add an extra byte to the data buffer to hold an I2C data/command byte 110 | # to use hardware-compatible I2C transactions. A memoryview of the 111 | # buffer is used to mask this byte from the framebuffer operations 112 | # (without a major memory hit as memoryview doesn't copy to a separate 113 | # buffer). 114 | self.buffer = bytearray(((height // 8) * width) + 1) 115 | self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1 116 | self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height) 117 | super().__init__(width, height, external_vcc) 118 | 119 | def write_cmd(self, cmd): 120 | self.temp[0] = 0x80 # Co=1, D/C#=0 121 | self.temp[1] = cmd 122 | self.i2c.writeto(self.addr, self.temp) 123 | 124 | def write_framebuf(self): 125 | # Blast out the frame buffer using a single I2C transaction to support 126 | # hardware I2C interfaces. 127 | self.i2c.writeto(self.addr, self.buffer) 128 | 129 | def poweron(self): 130 | pass 131 | 132 | 133 | class SSD1306_SPI(SSD1306): 134 | def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): 135 | self.rate = 10 * 1024 * 1024 136 | dc.init(dc.OUT, value=0) 137 | res.init(res.OUT, value=0) 138 | cs.init(cs.OUT, value=1) 139 | self.spi = spi 140 | self.dc = dc 141 | self.res = res 142 | self.cs = cs 143 | self.buffer = bytearray((height // 8) * width) 144 | self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height) 145 | super().__init__(width, height, external_vcc) 146 | 147 | def write_cmd(self, cmd): 148 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 149 | self.cs.value(1) 150 | self.dc.value(0) 151 | self.cs.value(0) 152 | self.spi.write(bytearray([cmd])) 153 | self.cs.value(1) 154 | 155 | def write_framebuf(self): 156 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 157 | self.cs.value(1) 158 | self.dc.value(1) 159 | self.cs.value(0) 160 | self.spi.write(self.buffer) 161 | self.cs.value(1) 162 | 163 | def poweron(self): 164 | self.res.value(1) 165 | time.sleep_ms(1) 166 | self.res.value(0) 167 | time.sleep_ms(10) 168 | self.res.value(1) 169 | -------------------------------------------------------------------------------- /Source_Ch08/WiPy/urtc.py: -------------------------------------------------------------------------------- 1 | import ucollections 2 | import utime 3 | 4 | 5 | DateTimeTuple = ucollections.namedtuple("DateTimeTuple", ["year", "month", 6 | "day", "weekday", "hour", "minute", "second", "millisecond"]) 7 | 8 | 9 | def datetime_tuple(year=None, month=None, day=None, weekday=None, hour=None, 10 | minute=None, second=None, millisecond=None): 11 | return DateTimeTuple(year, month, day, weekday, hour, minute, 12 | second, millisecond) 13 | 14 | 15 | def _bcd2bin(value): 16 | return (value or 0) - 6 * ((value or 0) >> 4) 17 | 18 | 19 | def _bin2bcd(value): 20 | return (value or 0) + 6 * ((value or 0) // 10) 21 | 22 | 23 | def tuple2seconds(datetime): 24 | return utime.mktime((datetime.year, datetime.month, datetime.day, 25 | datetime.hour, datetime.minute, datetime.second, datetime.weekday, 0)) 26 | 27 | 28 | def seconds2tuple(seconds): 29 | (year, month, day, hour, minute, 30 | second, weekday, _yday) = utime.localtime(seconds) 31 | return DateTimeTuple(year, month, day, weekday, hour, minute, second, 0) 32 | 33 | 34 | class _BaseRTC: 35 | _SWAP_DAY_WEEKDAY = False 36 | 37 | def __init__(self, i2c, address=0x68): 38 | self.i2c = i2c 39 | self.address = address 40 | 41 | def _register(self, register, buffer=None): 42 | if buffer is None: 43 | return self.i2c.readfrom_mem(self.address, register, 1)[0] 44 | self.i2c.writeto_mem(self.address, register, buffer) 45 | 46 | def _flag(self, register, mask, value=None): 47 | data = self._register(register) 48 | if value is None: 49 | return bool(data & mask) 50 | if value: 51 | data |= mask 52 | else: 53 | data &= ~mask 54 | self._register(register, bytearray((data,))) 55 | 56 | 57 | def datetime(self, datetime=None): 58 | if datetime is None: 59 | buffer = self.i2c.readfrom_mem(self.address, 60 | self._DATETIME_REGISTER, 7) 61 | if self._SWAP_DAY_WEEKDAY: 62 | day = buffer[3] 63 | weekday = buffer[4] 64 | else: 65 | day = buffer[4] 66 | weekday = buffer[3] 67 | return datetime_tuple( 68 | year=_bcd2bin(buffer[6]) + 2000, 69 | month=_bcd2bin(buffer[5]), 70 | day=_bcd2bin(day), 71 | weekday=_bcd2bin(weekday), 72 | hour=_bcd2bin(buffer[2]), 73 | minute=_bcd2bin(buffer[1]), 74 | second=_bcd2bin(buffer[0]), 75 | ) 76 | datetime = datetime_tuple(*datetime) 77 | buffer = bytearray(7) 78 | buffer[0] = _bin2bcd(datetime.second) 79 | buffer[1] = _bin2bcd(datetime.minute) 80 | buffer[2] = _bin2bcd(datetime.hour) 81 | if self._SWAP_DAY_WEEKDAY: 82 | buffer[4] = _bin2bcd(datetime.weekday) 83 | buffer[3] = _bin2bcd(datetime.day) 84 | else: 85 | buffer[3] = _bin2bcd(datetime.weekday) 86 | buffer[4] = _bin2bcd(datetime.day) 87 | buffer[5] = _bin2bcd(datetime.month) 88 | buffer[6] = _bin2bcd(datetime.year - 2000) 89 | self._register(self._DATETIME_REGISTER, buffer) 90 | 91 | 92 | class DS1307(_BaseRTC): 93 | _NVRAM_REGISTER = 0x08 94 | _DATETIME_REGISTER = 0x00 95 | _SQUARE_WAVE_REGISTER = 0x07 96 | 97 | def stop(self, value=None): 98 | return self._flag(0x00, 0b10000000, value) 99 | 100 | def memory(self, address, buffer=None): 101 | if buffer is not None and address + len(buffer) > 56: 102 | raise ValueError("address out of range") 103 | return self._register(self._NVRAM_REGISTER + address, buffer) 104 | 105 | 106 | class DS3231(_BaseRTC): 107 | _CONTROL_REGISTER = 0x0e 108 | _STATUS_REGISTER = 0x0f 109 | _DATETIME_REGISTER = 0x00 110 | _ALARM_REGISTERS = (0x08, 0x0b) 111 | _SQUARE_WAVE_REGISTER = 0x0e 112 | 113 | def lost_power(self): 114 | return self._flag(self._STATUS_REGISTER, 0b10000000) 115 | 116 | def alarm(self, value=None, alarm=0): 117 | return self._flag(self._STATUS_REGISTER, 118 | 0b00000011 & (1 << alarm), value) 119 | 120 | def stop(self, value=None): 121 | return self._flag(self._CONTROL_REGISTER, 0b10000000, value) 122 | 123 | def datetime(self, datetime=None): 124 | if datetime is not None: 125 | status = self._register(self._STATUS_REGISTER) & 0b01111111 126 | self._register(self._STATUS_REGISTER, bytearray((status,))) 127 | return super().datetime(datetime) 128 | 129 | def alarm_time(self, datetime=None, alarm=0): 130 | if datetime is None: 131 | buffer = self.i2c.readfrom_mem(self.address, 132 | self._ALARM_REGISTERS[alarm], 3) 133 | day = None 134 | weekday = None 135 | second = None 136 | if buffer[2] & 0b10000000: 137 | pass 138 | elif buffer[2] & 0b01000000: 139 | day = _bcd2bin(buffer[2] & 0x3f) 140 | else: 141 | weekday = _bcd2bin(buffer[2] & 0x3f) 142 | minute = (_bcd2bin(buffer[0] & 0x7f) 143 | if not buffer[0] & 0x80 else None) 144 | hour = (_bcd2bin(buffer[1] & 0x7f) 145 | if not buffer[1] & 0x80 else None) 146 | if alarm == 0: 147 | # handle seconds 148 | buffer = self.i2c.readfrom_mem( 149 | self.address, self._ALARM_REGISTERS[alarm] - 1, 1) 150 | second = (_bcd2bin(buffer[0] & 0x7f) 151 | if not buffer[0] & 0x80 else None) 152 | return datetime_tuple( 153 | day=day, 154 | weekday=weekday, 155 | hour=hour, 156 | minute=minute, 157 | second=second, 158 | ) 159 | datetime = datetime_tuple(*datetime) 160 | buffer = bytearray(3) 161 | buffer[0] = (_bin2bcd(datetime.minute) 162 | if datetime.minute is not None else 0x80) 163 | buffer[1] = (_bin2bcd(datetime.hour) 164 | if datetime.hour is not None else 0x80) 165 | if datetime.day is not None: 166 | if datetime.weekday is not None: 167 | raise ValueError("can't specify both day and weekday") 168 | buffer[2] = _bin2bcd(datetime.day) | 0b01000000 169 | elif datetime.weekday is not None: 170 | buffer[2] = _bin2bcd(datetime.weekday) 171 | else: 172 | buffer[2] = 0x80 173 | self._register(self._ALARM_REGISTERS[alarm], buffer) 174 | if alarm == 0: 175 | # handle seconds 176 | buffer = bytearray([_bin2bcd(datetime.second) 177 | if datetime.second is not None else 0x80]) 178 | self._register(self._ALARM_REGISTERS[alarm] - 1, buffer) 179 | 180 | 181 | 182 | class PCF8523(_BaseRTC): 183 | _CONTROL1_REGISTER = 0x00 184 | _CONTROL2_REGISTER = 0x01 185 | _CONTROL3_REGISTER = 0x02 186 | _DATETIME_REGISTER = 0x03 187 | _ALARM_REGISTER = 0x0a 188 | _SQUARE_WAVE_REGISTER = 0x0f 189 | _SWAP_DAY_WEEKDAY = True 190 | 191 | def __init__(self, *args, **kwargs): 192 | super().__init__(*args, **kwargs) 193 | self.init() 194 | 195 | def init(self): 196 | # Enable battery switchover and low-battery detection. 197 | self._flag(self._CONTROL3_REGISTER, 0b11100000, False) 198 | 199 | def reset(self): 200 | self._flag(self._CONTROL1_REGISTER, 0x58, True) 201 | self.init() 202 | 203 | def lost_power(self, value=None): 204 | return self._flag(self._CONTROL3_REGISTER, 0b00010000, value) 205 | 206 | def stop(self, value=None): 207 | return self._flag(self._CONTROL1_REGISTER, 0b00010000, value) 208 | 209 | def battery_low(self): 210 | return self._flag(self._CONTROL3_REGISTER, 0b00000100) 211 | 212 | def alarm(self, value=None): 213 | return self._flag(self._CONTROL2_REGISTER, 0b00001000, value) 214 | 215 | def datetime(self, datetime=None): 216 | if datetime is not None: 217 | self.lost_power(False) # clear the battery switchover flag 218 | return super().datetime(datetime) 219 | 220 | def alarm_time(self, datetime=None): 221 | if datetime is None: 222 | buffer = self.i2c.readfrom_mem(self.address, 223 | self._ALARM_REGISTER, 4) 224 | return datetime_tuple( 225 | weekday=_bcd2bin(buffer[3] & 226 | 0x7f) if not buffer[3] & 0x80 else None, 227 | day=_bcd2bin(buffer[2] & 228 | 0x7f) if not buffer[2] & 0x80 else None, 229 | hour=_bcd2bin(buffer[1] & 230 | 0x7f) if not buffer[1] & 0x80 else None, 231 | minute=_bcd2bin(buffer[0] & 232 | 0x7f) if not buffer[0] & 0x80 else None, 233 | ) 234 | datetime = datetime_tuple(*datetime) 235 | buffer = bytearray(4) 236 | buffer[0] = (_bin2bcd(datetime.minute) 237 | if datetime.minute is not None else 0x80) 238 | buffer[1] = (_bin2bcd(datetime.hour) 239 | if datetime.hour is not None else 0x80) 240 | buffer[2] = (_bin2bcd(datetime.day) 241 | if datetime.day is not None else 0x80) 242 | buffer[3] = (_bin2bcd(datetime.weekday) | 0b01000000 243 | if datetime.weekday is not None else 0x80) 244 | self._register(self._ALARM_REGISTER, buffer) 245 | -------------------------------------------------------------------------------- /Source_Ch08/clock_pyb_wipy.diff: -------------------------------------------------------------------------------- 1 | --- ./clock.py 2017-07-22 11:41:37.000000000 -0400 2 | +++ ./WiPy/clock.py 2017-07-22 11:41:10.000000000 -0400 3 | @@ -7,24 +7,22 @@ 4 | # - OLED SPI display 5 | # - RTC I2C module 6 | # 7 | -# Note: this only runs on the Pyboard. See chapter text 8 | -# for how to modify this to run on the WiPy 9 | +# Note: this only runs on the WiPy. See chapter text 10 | +# for how to modify this to run on the Pyboard 11 | # 12 | 13 | # Imports for the project 14 | -import pyb 15 | import urtc 16 | -from machine import SPI, Pin as pin 17 | -from pyb import I2C 18 | +import utime 19 | +from machine import SPI, I2C, RTC as rtc, Pin as pin 20 | from ssd1306 import SSD1306_SPI as ssd 21 | 22 | # Setup SPI and I2C 23 | -spi = SPI(2, baudrate=8000000, polarity=0, phase=0) 24 | -i2c = I2C(1, I2C.MASTER) 25 | -i2c.init(I2C.MASTER, baudrate=500000) 26 | +spi = SPI(0, SPI.MASTER, baudrate=2000000, polarity=0, phase=0) 27 | +i2c = I2C(0, I2C.MASTER, baudrate=100000,pins=("P9", "P8")) 28 | 29 | # Setup the OLED : D/C, RST, CS 30 | -oled_module = ssd(128,32,spi,pin("Y4"),pin("Y3"),pin("Y5")) 31 | +oled_module = ssd(128,32,spi,pin('P5'),pin('P6'),pin('P7')) 32 | 33 | # Setup the RTC 34 | rtc_module = urtc.DS1307(i2c) 35 | @@ -71,4 +69,4 @@ 36 | while True: 37 | clear_screen(oled_module) 38 | write_time(oled_module, rtc_module) 39 | - pyb.delay(1000) 40 | + utime.sleep(1) -------------------------------------------------------------------------------- /Source_Ch08/oled_test.py: -------------------------------------------------------------------------------- 1 | import machine 2 | from machine import Pin as pin 3 | from ssd1306 import SSD1306_SPI as ssd 4 | spi = machine.SPI(2, baudrate=8000000, polarity=0, phase=0) 5 | oled = ssd(128,32,spi,pin("Y4"),pin("Y3"),pin("Y5")) 6 | oled.fill(0) 7 | oled.show() 8 | oled.fill(1) 9 | oled.show() 10 | oled.fill(0) 11 | oled.show() 12 | oled.text("Hello, World!", 0, 0) 13 | oled.show() 14 | -------------------------------------------------------------------------------- /Source_Ch08/rtc_test.py: -------------------------------------------------------------------------------- 1 | import urtc 2 | from pyb import I2C 3 | from machine import Pin as pin 4 | i2c = I2C(1, I2C.MASTER) 5 | i2c.init(I2C.MASTER, baudrate=500000) 6 | i2c.scan() 7 | rtc = urtc.DS1307(i2c) 8 | # year, month, day, weekday, hour, minute, second, millisecond) 9 | start_datetime = (2017,07,20,4,7,25,0,0) 10 | rtc.datetime(start_datetime) 11 | print(rtc.datetime()) 12 | -------------------------------------------------------------------------------- /Source_Ch08/ssd1306_pyb.diff: -------------------------------------------------------------------------------- 1 | --- /Users/cbell/Downloads/Adafruit-uRTC-master_orig/urtc.py 2017-04-21 16:52:32.000000000 -0400 2 | +++ /Users/cbell/Downloads/Adafruit-uRTC-master/urtc.py 2017-07-20 19:20:38.000000000 -0400 3 | @@ -40,8 +40,8 @@ 4 | 5 | def _register(self, register, buffer=None): 6 | if buffer is None: 7 | - return self.i2c.readfrom_mem(self.address, register, 1)[0] 8 | - self.i2c.writeto_mem(self.address, register, buffer) 9 | + return self.i2c.mem_read(1, self.address, register)[0] 10 | + self.i2c.mem_write(buffer, self.address, register) 11 | 12 | def _flag(self, register, mask, value=None): 13 | data = self._register(register) 14 | @@ -56,8 +56,8 @@ 15 | 16 | def datetime(self, datetime=None): 17 | if datetime is None: 18 | - buffer = self.i2c.readfrom_mem(self.address, 19 | - self._DATETIME_REGISTER, 7) 20 | + buffer = self.i2c.mem_read(7, self.address, 21 | + self._DATETIME_REGISTER) 22 | if self._SWAP_DAY_WEEKDAY: 23 | day = buffer[3] 24 | weekday = buffer[4] 25 | @@ -128,8 +128,8 @@ 26 | 27 | def alarm_time(self, datetime=None, alarm=0): 28 | if datetime is None: 29 | - buffer = self.i2c.readfrom_mem(self.address, 30 | - self._ALARM_REGISTERS[alarm], 3) 31 | + buffer = self.i2c.mem_read(3, self.address, 32 | + self._ALARM_REGISTERS[alarm]) 33 | day = None 34 | weekday = None 35 | second = None 36 | @@ -145,8 +145,8 @@ 37 | if not buffer[1] & 0x80 else None) 38 | if alarm == 0: 39 | # handle seconds 40 | - buffer = self.i2c.readfrom_mem( 41 | - self.address, self._ALARM_REGISTERS[alarm] - 1, 1) 42 | + buffer = self.i2c.mem_read(1, 43 | + self.address, self._ALARM_REGISTERS[alarm] - 1) 44 | second = (_bcd2bin(buffer[0] & 0x7f) 45 | if not buffer[0] & 0x80 else None) 46 | return datetime_tuple( 47 | @@ -219,8 +219,8 @@ 48 | 49 | def alarm_time(self, datetime=None): 50 | if datetime is None: 51 | - buffer = self.i2c.readfrom_mem(self.address, 52 | - self._ALARM_REGISTER, 4) 53 | + buffer = self.i2c.mem_read(4, self.address, 54 | + self._ALARM_REGISTER) 55 | return datetime_tuple( 56 | weekday=_bcd2bin(buffer[3] & 57 | 0x7f) if not buffer[3] & 0x80 else None, 58 | -------------------------------------------------------------------------------- /Source_Ch08/ssd1306_wipy.diff: -------------------------------------------------------------------------------- 1 | --- ./Pyboard/ssd1306.py 2016-10-30 14:06:02.000000000 -0400 2 | +++ ./WiPy/ssd1306.py 2017-07-20 21:39:31.000000000 -0400 3 | @@ -146,23 +146,23 @@ 4 | 5 | def write_cmd(self, cmd): 6 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 7 | - self.cs.high() 8 | - self.dc.low() 9 | - self.cs.low() 10 | + self.cs.value(1) 11 | + self.dc.value(0) 12 | + self.cs.value(0) 13 | self.spi.write(bytearray([cmd])) 14 | - self.cs.high() 15 | + self.cs.value(1) 16 | 17 | def write_framebuf(self): 18 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 19 | - self.cs.high() 20 | - self.dc.high() 21 | - self.cs.low() 22 | + self.cs.value(1) 23 | + self.dc.value(1) 24 | + self.cs.value(0) 25 | self.spi.write(self.buffer) 26 | - self.cs.high() 27 | + self.cs.value(1) 28 | 29 | def poweron(self): 30 | - self.res.high() 31 | + self.res.value(1) 32 | time.sleep_ms(1) 33 | - self.res.low() 34 | + self.res.value(0) 35 | time.sleep_ms(10) 36 | - self.res.high() 37 | + self.res.value(1) 38 | -------------------------------------------------------------------------------- /Source_Ch08/urtc_pyboard.diff: -------------------------------------------------------------------------------- 1 | --- /Users/cbell/Downloads/Adafruit-uRTC-master 3/urtc.py 2017-04-21 16:52:32.000000000 -0400 2 | +++ /Users/cbell/Documents/Writing/MicroPython for the IOT/source/Ch08/Pyboard/urtc.py 2017-07-20 19:20:38.000000000 -0400 3 | @@ -40,8 +40,8 @@ 4 | 5 | def _register(self, register, buffer=None): 6 | if buffer is None: 7 | - return self.i2c.readfrom_mem(self.address, register, 1)[0] 8 | - self.i2c.writeto_mem(self.address, register, buffer) 9 | + return self.i2c.mem_read(1, self.address, register)[0] 10 | + self.i2c.mem_write(buffer, self.address, register) 11 | 12 | def _flag(self, register, mask, value=None): 13 | data = self._register(register) 14 | @@ -56,8 +56,8 @@ 15 | 16 | def datetime(self, datetime=None): 17 | if datetime is None: 18 | - buffer = self.i2c.readfrom_mem(self.address, 19 | - self._DATETIME_REGISTER, 7) 20 | + buffer = self.i2c.mem_read(7, self.address, 21 | + self._DATETIME_REGISTER) 22 | if self._SWAP_DAY_WEEKDAY: 23 | day = buffer[3] 24 | weekday = buffer[4] 25 | @@ -128,8 +128,8 @@ 26 | 27 | def alarm_time(self, datetime=None, alarm=0): 28 | if datetime is None: 29 | - buffer = self.i2c.readfrom_mem(self.address, 30 | - self._ALARM_REGISTERS[alarm], 3) 31 | + buffer = self.i2c.mem_read(3, self.address, 32 | + self._ALARM_REGISTERS[alarm]) 33 | day = None 34 | weekday = None 35 | second = None 36 | @@ -145,8 +145,8 @@ 37 | if not buffer[1] & 0x80 else None) 38 | if alarm == 0: 39 | # handle seconds 40 | - buffer = self.i2c.readfrom_mem( 41 | - self.address, self._ALARM_REGISTERS[alarm] - 1, 1) 42 | + buffer = self.i2c.mem_read(1, 43 | + self.address, self._ALARM_REGISTERS[alarm] - 1) 44 | second = (_bcd2bin(buffer[0] & 0x7f) 45 | if not buffer[0] & 0x80 else None) 46 | return datetime_tuple( 47 | @@ -219,8 +219,8 @@ 48 | 49 | def alarm_time(self, datetime=None): 50 | if datetime is None: 51 | - buffer = self.i2c.readfrom_mem(self.address, 52 | - self._ALARM_REGISTER, 4) 53 | + buffer = self.i2c.mem_read(4, self.address, 54 | + self._ALARM_REGISTER) 55 | return datetime_tuple( 56 | weekday=_bcd2bin(buffer[3] & 57 | 0x7f) if not buffer[3] & 0x80 else None, 58 | -------------------------------------------------------------------------------- /Source_Ch09/Pyboard/ped_part1_pyb.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 9 2 | # 3 | # Project 2: A MicroPython Pedestrian Crosswalk Simulator 4 | # Part 1 - controlling LEDs and button as input 5 | # 6 | # Required Components: 7 | # - Pyboard 8 | # - (2) Red LEDs 9 | # - (2) Yellow LEDs 10 | # - (1) Green LED 11 | # - (5) 220 Ohm resistors 12 | # - (1) breadboard friendly momentary button 13 | # 14 | # Note: this only runs on the Pyboard. 15 | # 16 | # Imports for the project 17 | from pyb import Pin, delay, ExtInt 18 | 19 | # Setup the button and LEDs 20 | button = Pin('X1', Pin.IN, Pin.PULL_UP) 21 | led1 = Pin('X7', Pin.OUT_PP) 22 | led2 = Pin('X6', Pin.OUT_PP) 23 | led3 = Pin('X5', Pin.OUT_PP) 24 | led4 = Pin('X4', Pin.OUT_PP) 25 | led5 = Pin('X3', Pin.OUT_PP) 26 | 27 | # Setup lists for the LEDs 28 | stoplight = [led1, led2, led3] 29 | walklight = [led4, led5] 30 | 31 | # Turn off the LEDs 32 | for led in stoplight: 33 | led.low() 34 | for led in walklight: 35 | led.low() 36 | 37 | # Start with green stoplight and red walklight 38 | stoplight[2].high() 39 | walklight[0].high() 40 | 41 | # We need a method to cycle the stoplight and walklight 42 | # 43 | # We toggle from green to yellow for 2 seconds 44 | # then red for 20 seconds. 45 | def cycle_lights(): 46 | # Go yellow. 47 | stoplight[2].low() 48 | stoplight[1].high() 49 | # Wait 2 seconds 50 | delay(2000) 51 | # Go red and turn on walk light 52 | stoplight[1].low() 53 | stoplight[0].high() 54 | delay(500) # Give the pedestrian a chance to see it 55 | walklight[0].low() 56 | walklight[1].high() 57 | # After 10 seconds, start blinking the walk light 58 | delay(10000) 59 | for i in range(0,10): 60 | walklight[1].low() 61 | delay(500) 62 | walklight[1].high() 63 | delay(500) 64 | 65 | # Stop=green, walk=red 66 | walklight[1].low() 67 | walklight[0].high() 68 | delay(500) # Give the pedestrian a chance to see it 69 | stoplight[0].low() 70 | stoplight[2].high() 71 | 72 | # Create callback for the button 73 | def button_pressed(line): 74 | cur_value = button.value() 75 | active = 0 76 | while (active < 50): 77 | if button.value() != cur_value: 78 | active += 1 79 | else: 80 | active = 0 81 | delay(1) 82 | print("") 83 | if active: 84 | cycle_lights() 85 | else: 86 | print("False press") 87 | 88 | # Create an interrupt for the button 89 | e = ExtInt('X1', ExtInt.IRQ_FALLING, Pin.PULL_UP, button_pressed) 90 | 91 | -------------------------------------------------------------------------------- /Source_Ch09/Pyboard/ped_part2_pyb.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 9 2 | # 3 | # Project 2: A MicroPython Pedestrian Crosswalk Simulator 4 | # Part 2 - Controlling the walklight remotely 5 | # 6 | # Required Components: 7 | # - Pyboard 8 | # - (2) Red LEDs 9 | # - (2) Yellow LEDs 10 | # - (1) Green LED 11 | # - (5) 220 Ohm resistors 12 | # - (1) breadboard friendly momentary button 13 | # - (1) CC3000 breakout board 14 | # 15 | # Note: this only runs on the Pyboard. 16 | # 17 | # Imports for the project 18 | from pyb import Pin, delay, ExtInt, SPI 19 | import network 20 | import usocket as socket 21 | 22 | # Setup network connection 23 | nic = network.CC3K(SPI(2), Pin.board.Y5, Pin.board.Y4, Pin.board.Y3) 24 | # Replace the following with yout SSID and password 25 | nic.connect("YOUR_SSID", "YOUR_PASSWORD") 26 | print("Connecting...") 27 | while not nic.isconnected(): 28 | delay(50) 29 | print("Connected!") 30 | print("My IP address is: {0}".format(nic.ifconfig()[0])) 31 | 32 | # HTML web page for the project 33 | HTML_RESPONSE = """ 34 | 35 |
36 |Pedestrian Stoplight Simulation
8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Source_Ch10/Pyboard/plant_monitor.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 10 2 | # 3 | # Project 3: MicroPython Plant Monitoring 4 | # 5 | # Plant monitor class 6 | # 7 | # Note: this only runs on the Pyboard. 8 | from pyb import ADC, delay, Pin, SD 9 | import os 10 | import pyb 11 | 12 | # Thresholds for the sensors 13 | LOWER_THRESHOLD = 500 14 | UPPER_THRESHOLD = 2500 15 | UPDATE_FREQ = 120 # seconds 16 | 17 | # File name for the data 18 | SENSOR_DATA = "plant_data.csv" 19 | 20 | # Format the time (epoch) for a better view 21 | def _format_time(tm_data): 22 | # Use a special shortcut to unpack tuple: *tm_data 23 | return "{0}-{1:0>2}-{2:0>2} {3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data) 24 | 25 | class PlantMonitor: 26 | """ 27 | This class reads soil moisture from one or more sensors and writes the 28 | data to a comma-separated value (csv) file as specified in the constructor. 29 | """ 30 | 31 | # Initialization for the class (the constructor) 32 | def __init__(self, rtc): 33 | self.rtc = rtc 34 | 35 | # Try to access the SD card and make the new path 36 | try: 37 | self.sensor_file = "/sd/{0}".format(filename) 38 | f = open(self.sensor_file, 'r') 39 | f.close() 40 | print("INFO: Using SD card for data.") 41 | except: 42 | print("ERROR: cannot mount SD card, reverting to flash!") 43 | self.sensor_file = SENSOR_DATA 44 | print("Data filename = {0}".format(self.sensor_file)) 45 | 46 | # Setup the dictionary for each soil moisture sensor 47 | soil_moisture1 = { 48 | 'sensor': ADC(Pin('X19')), 49 | 'power': Pin('X20', Pin.OUT_PP), 50 | 'location': 'Green ceramic pot on top shelf', 51 | 'num': 1, 52 | } 53 | soil_moisture2 = { 54 | 'sensor': ADC(Pin('X20')), 55 | 'power': Pin('X21', Pin.OUT_PP), 56 | 'location': 'Fern on bottom shelf', 57 | 'num': 2, 58 | } 59 | # Setup a list for each sensor dictionary 60 | self.sensors = [soil_moisture1, soil_moisture2] 61 | # Setup the alarm to read the sensors 62 | self.alarm = pyb.millis() 63 | print("Plant Monitor class is ready...") 64 | 65 | # Clear the log 66 | def clear_log(self): 67 | log_file = open(self.sensor_file, 'w') 68 | log_file.close() 69 | 70 | # Get the filename we're using after the check for SD card 71 | def get_filename(self): 72 | return self.sensor_file 73 | 74 | # Read the sensor 10 times and average the values read 75 | def _get_value(self, sensor, power): 76 | total = 0 77 | # Turn power on 78 | power.high() 79 | for i in range (0,10): 80 | # Wait for sensor to power on and settle 81 | delay(5000) 82 | # Read the value 83 | value = sensor.read() 84 | total += value 85 | # Turn sensor off 86 | power.low() 87 | return int(total/10) 88 | 89 | # Monitor the sensors, read the values and save them 90 | def read_sensors(self): 91 | if pyb.elapsed_millis(self.alarm) < (UPDATE_FREQ * 1000): 92 | return 93 | self.alarm = pyb.millis() 94 | log_file = open(self.sensor_file, 'a') 95 | for sensor in self.sensors: 96 | # Read the data from the sensor and convert the value 97 | value = self._get_value(sensor['sensor'], sensor['power']) 98 | print("Value read: {0}".format(value)) 99 | time_data = self.rtc.datetime() 100 | # datetime,num,value,enum,location 101 | log_file.write( 102 | "{0},{1},{2},{3},{4}\n".format(_format_time(time_data), 103 | sensor['num'], value, 104 | self._convert_value(value), 105 | sensor['location'])) 106 | log_file.close() 107 | 108 | # Convert the raw sensor value to an enumeration 109 | def _convert_value(self, value): 110 | # If value is less than lower threshold, soil is dry else if it 111 | # is greater than upper threshold, it is wet, else all is well. 112 | if (value <= LOWER_THRESHOLD): 113 | return "dry" 114 | elif (value >= UPPER_THRESHOLD): 115 | return "wet" 116 | return "ok" 117 | -------------------------------------------------------------------------------- /Source_Ch10/Pyboard/plant_pyboard.py: -------------------------------------------------------------------------------- 1 | # MicroPython for the IOT - Chapter 10 2 | # 3 | # Project 3: MicroPython Plant Monitoring 4 | # 5 | # Required Components: 6 | # - Pyboard 7 | # - (N) Soil moisture sensors (one for each plant) 8 | # 9 | # Note: this only runs on the Pyboard. 10 | # 11 | # Imports for the project 12 | from pyb import delay, SPI 13 | from pyb import I2C 14 | import network 15 | import urtc 16 | import usocket as socket 17 | from plant_monitor import PlantMonitor 18 | 19 | # Setup the I2C interface for the rtc 20 | i2c = I2C(1, I2C.MASTER) 21 | i2c.init(I2C.MASTER, baudrate=500000) 22 | 23 | # HTML web page for the project 24 | HTML_TABLE_ROW = "Datetime | Sensor Number | Raw Value | Moisture | Location |
---|
Datetime | Sensor Number | Raw Value | Moisture | Location |
---|---|---|---|---|
13:41:10 05/15/2017 | 1 | 220 | Ok | Small fern on bottom shelf on porch |
13:41:15 05/15/2017 | 2 | 299 | Ok | Green thing on bottom shelf on porch |
13:41:22 05/15/2017 | 3 | 118 | Dry | Flowers on top shelf on porch |
13:41:31 05/15/2017 | 4 | 500 | Wet | Creeper on middle shelf on porch |