From c8bdf2064349f694b43f2e69a71fb0c3882a6455 Mon Sep 17 00:00:00 2001 From: "ELECFREAKS.Admin" Date: Wed, 10 May 2023 09:56:27 +0800 Subject: [PATCH] Add files via upload --- Octopus_CircuitPython_V1.0.0/DHT11/code.py | 8 + .../DHT11/lib/DHT11.py | 14 + .../DHT11/lib/adafruit_dht.py | 319 +++++++++ Octopus_CircuitPython_V1.0.0/Distance/code.py | 8 + .../Distance/lib/Distance.py | 12 + .../Distance/lib/adafruit_hcsr04.py | 180 +++++ Octopus_CircuitPython_V1.0.0/Fan/code.py | 9 + Octopus_CircuitPython_V1.0.0/Fan/lib/Fan.py | 12 + .../Fan/lib/adafruit_motor/__init__.mpy | Bin 0 -> 42 bytes .../Fan/lib/adafruit_motor/motor.mpy | Bin 0 -> 1115 bytes .../Fan/lib/adafruit_motor/servo.mpy | Bin 0 -> 1458 bytes .../Fan/lib/adafruit_motor/stepper.mpy | Bin 0 -> 1794 bytes Octopus_CircuitPython_V1.0.0/LED/code.py | 12 + Octopus_CircuitPython_V1.0.0/LED/lib/LED.py | 19 + Octopus_CircuitPython_V1.0.0/Light/code.py | 9 + .../Light/lib/Light.py | 11 + Octopus_CircuitPython_V1.0.0/Noise/code.py | 8 + .../Noise/lib/Noise.py | 11 + Octopus_CircuitPython_V1.0.0/OLED/code.py | 27 + Octopus_CircuitPython_V1.0.0/OLED/font5x8.bin | Bin 0 -> 1282 bytes Octopus_CircuitPython_V1.0.0/OLED/lib/OLED.py | 70 ++ .../OLED/lib/adafruit_framebuf.py | 639 ++++++++++++++++++ .../OLED/lib/adafruit_ssd1306.py | 352 ++++++++++ Octopus_CircuitPython_V1.0.0/README.md | 2 + Octopus_CircuitPython_V1.0.0/Servo/code.py | 9 + .../Servo/lib/Servo.py | 14 + .../Servo/lib/adafruit_motor/__init__.mpy | Bin 0 -> 42 bytes .../Servo/lib/adafruit_motor/motor.mpy | Bin 0 -> 1115 bytes .../Servo/lib/adafruit_motor/servo.mpy | Bin 0 -> 1458 bytes .../Servo/lib/adafruit_motor/stepper.mpy | Bin 0 -> 1794 bytes Octopus_CircuitPython_V1.0.0/Trimpot/code.py | 11 + .../Trimpot/lib/Trimpot.py | 11 + .../Waterlevel/code.py | 9 + .../Waterlevel/lib/Waterlevel.py | 11 + 34 files changed, 1787 insertions(+) create mode 100644 Octopus_CircuitPython_V1.0.0/DHT11/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/DHT11/lib/DHT11.py create mode 100644 Octopus_CircuitPython_V1.0.0/DHT11/lib/adafruit_dht.py create mode 100644 Octopus_CircuitPython_V1.0.0/Distance/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Distance/lib/Distance.py create mode 100644 Octopus_CircuitPython_V1.0.0/Distance/lib/adafruit_hcsr04.py create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/lib/Fan.py create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/__init__.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/motor.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/servo.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/stepper.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/LED/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/LED/lib/LED.py create mode 100644 Octopus_CircuitPython_V1.0.0/Light/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Light/lib/Light.py create mode 100644 Octopus_CircuitPython_V1.0.0/Noise/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Noise/lib/Noise.py create mode 100644 Octopus_CircuitPython_V1.0.0/OLED/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/OLED/font5x8.bin create mode 100644 Octopus_CircuitPython_V1.0.0/OLED/lib/OLED.py create mode 100644 Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_framebuf.py create mode 100644 Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_ssd1306.py create mode 100644 Octopus_CircuitPython_V1.0.0/README.md create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/lib/Servo.py create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/__init__.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/motor.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/servo.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/stepper.mpy create mode 100644 Octopus_CircuitPython_V1.0.0/Trimpot/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Trimpot/lib/Trimpot.py create mode 100644 Octopus_CircuitPython_V1.0.0/Waterlevel/code.py create mode 100644 Octopus_CircuitPython_V1.0.0/Waterlevel/lib/Waterlevel.py diff --git a/Octopus_CircuitPython_V1.0.0/DHT11/code.py b/Octopus_CircuitPython_V1.0.0/DHT11/code.py new file mode 100644 index 0000000..9b5dc75 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/DHT11/code.py @@ -0,0 +1,8 @@ +from DHT11 import * +import time + +dht11 = DHT11(board.GP26) + +while True: + print("Temp: {:.1f} *C \t Humidity: {}%".format(dht11.get_temperature(), dht11.get_humidity())) + time.sleep(1) \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/DHT11/lib/DHT11.py b/Octopus_CircuitPython_V1.0.0/DHT11/lib/DHT11.py new file mode 100644 index 0000000..b127cda --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/DHT11/lib/DHT11.py @@ -0,0 +1,14 @@ +import adafruit_dht +import board + + +class DHT11: + def __init__(self, pin): + self.pin = pin + self.dht = adafruit_dht.DHT11(self.pin) + + def get_temperature(self): + return self.dht.temperature + + def get_humidity(self): + return self.dht.humidity diff --git a/Octopus_CircuitPython_V1.0.0/DHT11/lib/adafruit_dht.py b/Octopus_CircuitPython_V1.0.0/DHT11/lib/adafruit_dht.py new file mode 100644 index 0000000..f173cd8 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/DHT11/lib/adafruit_dht.py @@ -0,0 +1,319 @@ +# SPDX-FileCopyrightText: 2017 Mike McWethy for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +:mod:`adafruit_dhtlib` +====================== + +CircuitPython support for the DHT11 and DHT22 temperature and humidity devices. + +* Author(s): Mike McWethy + +**Hardware:** + +* Adafruit `DHT22 temperature-humidity sensor + extras + `_ (Product ID: 385) + +* Adafruit `DHT11 basic temperature-humidity sensor + extras + `_ (Product ID: 386) + + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://circuitpython.org/downloads + +""" + +import array +import time +from os import uname +from digitalio import DigitalInOut, Pull, Direction + +_USE_PULSEIO = False +try: + from pulseio import PulseIn + + _USE_PULSEIO = True +except (ImportError, NotImplementedError): + pass # This is OK, we'll try to bitbang it! + +try: + # Used only for typing + from typing import Union + from microcontroller import Pin +except ImportError: + pass + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DHT.git" + + +class DHTBase: + """base support for DHT11 and DHT22 devices + + :param bool dht11: True if device is DHT11, otherwise DHT22. + :param ~board.Pin pin: digital pin used for communication + :param int trig_wait: length of time to hold trigger in LOW state (microseconds) + :param bool use_pulseio: False to force bitbang when pulseio available (only with Blinka) + """ + + __hiLevel = 51 + + def __init__( + self, + dht11: bool, + pin: Pin, + trig_wait: int, + use_pulseio: bool, + *, + max_pulses: int = 81 + ): + self._dht11 = dht11 + self._pin = pin + self._trig_wait = trig_wait + self._max_pulses = max_pulses + self._last_called = 0 + self._humidity = None + self._temperature = None + self._use_pulseio = use_pulseio + if "Linux" not in uname() and not self._use_pulseio: + raise Exception("Bitbanging is not supported when using CircuitPython.") + # We don't use a context because linux-based systems are sluggish + # and we're better off having a running process + if self._use_pulseio: + self.pulse_in = PulseIn(self._pin, maxlen=self._max_pulses, idle_state=True) + self.pulse_in.pause() + + def exit(self) -> None: + """Cleans up the PulseIn process. Must be called explicitly""" + if self._use_pulseio: + print("De-initializing self.pulse_in") + self.pulse_in.deinit() + + def _pulses_to_binary(self, pulses: array.array, start: int, stop: int) -> int: + """Takes pulses, a list of transition times, and converts + them to a 1's or 0's. The pulses array contains the transition times. + pulses starts with a low transition time followed by a high transistion time. + then a low followed by a high and so on. The low transition times are + ignored. Only the high transition times are used. If the high + transition time is greater than __hiLevel, that counts as a bit=1, if the + high transition time is less that __hiLevel, that counts as a bit=0. + + start is the starting index in pulses to start converting + + stop is the index to convert upto but not including + + Returns an integer containing the converted 1 and 0 bits + """ + + binary = 0 + hi_sig = False + for bit_inx in range(start, stop): + if hi_sig: + bit = 0 + if pulses[bit_inx] > self.__hiLevel: + bit = 1 + binary = binary << 1 | bit + + hi_sig = not hi_sig + + return binary + + def _get_pulses_pulseio(self) -> array.array: + """_get_pulses implements the communication protocol for + DHT11 and DHT22 type devices. It sends a start signal + of a specific length and listens and measures the + return signal lengths. + + return pulses (array.array uint16) contains alternating high and low + transition times starting with a low transition time. Normally + pulses will have 81 elements for the DHT11/22 type devices. + """ + pulses = array.array("H") + if self._use_pulseio: + # The DHT type device use a specialize 1-wire protocol + # The microprocessor first sends a LOW signal for a + # specific length of time. Then the device sends back a + # series HIGH and LOW signals. The length the HIGH signals + # represents the device values. + self.pulse_in.clear() + self.pulse_in.resume(self._trig_wait) + + # loop until we get the return pulse we need or + # time out after 1/4 second + time.sleep(0.25) + self.pulse_in.pause() + while self.pulse_in: + pulses.append(self.pulse_in.popleft()) + return pulses + + def _get_pulses_bitbang(self) -> array.array: + """_get_pulses implements the communication protcol for + DHT11 and DHT22 type devices. It sends a start signal + of a specific length and listens and measures the + return signal lengths. + + return pulses (array.array uint16) contains alternating high and low + transition times starting with a low transition time. Normally + pulses will have 81 elements for the DHT11/22 type devices. + """ + pulses = array.array("H") + with DigitalInOut(self._pin) as dhtpin: + # we will bitbang if no pulsein capability + transitions = [] + # Signal by setting pin high, then low, and releasing + dhtpin.direction = Direction.OUTPUT + dhtpin.value = True + time.sleep(0.1) + dhtpin.value = False + # Using the time to pull-down the line according to DHT Model + time.sleep(self._trig_wait / 1000000) + timestamp = time.monotonic() # take timestamp + dhtval = True # start with dht pin true because its pulled up + dhtpin.direction = Direction.INPUT + + try: + dhtpin.pull = Pull.UP + # Catch the NotImplementedError raised because + # blinka.microcontroller.generic_linux.libgpiod_pin does not support + # internal pull resistors. + except NotImplementedError: + dhtpin.pull = None + + while time.monotonic() - timestamp < 0.25: + if dhtval != dhtpin.value: + dhtval = not dhtval # we toggled + transitions.append(time.monotonic()) # save the timestamp + # convert transtions to microsecond delta pulses: + # use last 81 pulses + transition_start = max(1, len(transitions) - self._max_pulses) + for i in range(transition_start, len(transitions)): + pulses_micro_sec = int(1000000 * (transitions[i] - transitions[i - 1])) + pulses.append(min(pulses_micro_sec, 65535)) + return pulses + + def measure(self) -> None: + """measure runs the communications to the DHT11/22 type device. + if successful, the class properties temperature and humidity will + return the reading returned from the device. + + Raises RuntimeError exception for checksum failure and for insufficient + data returned from the device (try again) + """ + delay_between_readings = 2 # 2 seconds per read according to datasheet + # Initiate new reading if this is the first call or if sufficient delay + # If delay not sufficient - return previous reading. + # This allows back to back access for temperature and humidity for same reading + if ( + self._last_called == 0 + or (time.monotonic() - self._last_called) > delay_between_readings + ): + self._last_called = time.monotonic() + + new_temperature = 0 + new_humidity = 0 + + if self._use_pulseio: + pulses = self._get_pulses_pulseio() + else: + pulses = self._get_pulses_bitbang() + # print(len(pulses), "pulses:", [x for x in pulses]) + + if len(pulses) < 10: + # Probably a connection issue! + raise RuntimeError("DHT sensor not found, check wiring") + + if len(pulses) < 80: + # We got *some* data just not 81 bits + raise RuntimeError("A full buffer was not returned. Try again.") + + buf = array.array("B") + for byte_start in range(0, 80, 16): + buf.append(self._pulses_to_binary(pulses, byte_start, byte_start + 16)) + + if self._dht11: + # humidity is 1 byte + new_humidity = buf[0] + # temperature is 1 byte + new_temperature = buf[2] + else: + # humidity is 2 bytes + new_humidity = ((buf[0] << 8) | buf[1]) / 10 + # temperature is 2 bytes + # MSB is sign, bits 0-14 are magnitude) + new_temperature = (((buf[2] & 0x7F) << 8) | buf[3]) / 10 + # set sign + if buf[2] & 0x80: + new_temperature = -new_temperature + # calc checksum + chk_sum = 0 + for b in buf[0:4]: + chk_sum += b + + # checksum is the last byte + if chk_sum & 0xFF != buf[4]: + # check sum failed to validate + raise RuntimeError("Checksum did not validate. Try again.") + + if new_humidity < 0 or new_humidity > 100: + # We received unplausible data + raise RuntimeError("Received unplausible data. Try again.") + + self._temperature = new_temperature + self._humidity = new_humidity + + @property + def temperature(self) -> Union[int, float, None]: + """temperature current reading. It makes sure a reading is available + + Raises RuntimeError exception for checksum failure and for insufficient + data returned from the device (try again) + """ + self.measure() + return self._temperature + + @property + def humidity(self) -> Union[int, float, None]: + """humidity current reading. It makes sure a reading is available + + Raises RuntimeError exception for checksum failure and for insufficient + data returned from the device (try again) + """ + self.measure() + return self._humidity + + +class DHT11(DHTBase): + """Support for DHT11 device. + + :param ~board.Pin pin: digital pin used for communication + """ + + def __init__(self, pin: Pin, use_pulseio: bool = _USE_PULSEIO): + super().__init__(True, pin, 18000, use_pulseio) + + +class DHT22(DHTBase): + """Support for DHT22 device. + + :param ~board.Pin pin: digital pin used for communication + """ + + def __init__(self, pin: Pin, use_pulseio: bool = _USE_PULSEIO): + super().__init__(False, pin, 1000, use_pulseio) + + +class DHT21(DHTBase): + """Support for DHT21/AM2301 device. + + :param ~board.Pin pin: digital pin used for communication + """ + + # DHT21/AM2301 is sending three more dummy bytes after the "official" protocol. + # Pulseio will take only the last pulses up to maxPulses. + # If that would be 81, the dummy pulses will be read and the real data would be truncated. + # Hence setting maxPulses to 129, taking both real data and dummy bytes into buffer. + def __init__(self, pin: Pin, use_pulseio: bool = _USE_PULSEIO): + super().__init__(False, pin, 1000, use_pulseio, max_pulses=129) diff --git a/Octopus_CircuitPython_V1.0.0/Distance/code.py b/Octopus_CircuitPython_V1.0.0/Distance/code.py new file mode 100644 index 0000000..8f99570 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Distance/code.py @@ -0,0 +1,8 @@ +import time +from Distance import * + +distance = Distance(board.GP17, board.GP16) + +while True: + print(distance.get_distance(), "cm") + time.sleep(0.5) diff --git a/Octopus_CircuitPython_V1.0.0/Distance/lib/Distance.py b/Octopus_CircuitPython_V1.0.0/Distance/lib/Distance.py new file mode 100644 index 0000000..e9550b8 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Distance/lib/Distance.py @@ -0,0 +1,12 @@ +import board +import adafruit_hcsr04 + + +class Distance: + def __init__(self, pinTrigger, pinEcho): + self.pinTrigger = pinTrigger + self.pinEcho = pinEcho + self.sonar = adafruit_hcsr04.HCSR04(self.pinTrigger, self.pinEcho) + + def get_distance(self): + return self.sonar.distance diff --git a/Octopus_CircuitPython_V1.0.0/Distance/lib/adafruit_hcsr04.py b/Octopus_CircuitPython_V1.0.0/Distance/lib/adafruit_hcsr04.py new file mode 100644 index 0000000..35797e6 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Distance/lib/adafruit_hcsr04.py @@ -0,0 +1,180 @@ +# SPDX-FileCopyrightText: 2017 Mike Mabey +# +# SPDX-License-Identifier: MIT + +""" +`adafruit_hcsr04` +==================================================== + +A CircuitPython library for the HC-SR04 ultrasonic range sensor. + +The HC-SR04 functions by sending an ultrasonic signal, which is reflected by +many materials, and then sensing when the signal returns to the sensor. Knowing +that sound travels through dry air at `343.2 meters per second (at 20 °C) +`_, it's pretty straightforward +to calculate how far away the object is by timing how long the signal took to +go round-trip and do some simple arithmetic, which is handled for you by this +library. + +.. warning:: + + The HC-SR04 uses 5V logic, so you will have to use a `level shifter + `_ or simple + voltage divider between it and your CircuitPython board (which uses 3.3V logic) + +* Authors: + + - Mike Mabey + - Jerry Needell - modified to add timeout while waiting for echo (2/26/2018) + - ladyada - compatible with `distance` property standard, renaming, Pi compat +""" + +import time +from digitalio import DigitalInOut, Direction + +try: + from typing import Optional, Type + from types import TracebackType + from microcontroller import Pin +except ImportError: + pass + +_USE_PULSEIO = False +try: + from pulseio import PulseIn + + _USE_PULSEIO = True +except (ImportError, NotImplementedError): + pass # This is OK, we'll try to bitbang it! + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HCSR04.git" + + +class HCSR04: + """Control a HC-SR04 ultrasonic range sensor. + + Example use: + + :: + + import time + import board + + import adafruit_hcsr04 + + sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.D2, echo_pin=board.D3) + + + while True: + try: + print((sonar.distance,)) + except RuntimeError: + print("Retrying!") + pass + time.sleep(0.1) + """ + + def __init__( + self, trigger_pin: Pin, echo_pin: Pin, *, timeout: float = 0.1 + ) -> None: + """ + :param trigger_pin: The pin on the microcontroller that's connected to the + ``Trig`` pin on the HC-SR04. + :type trig_pin: microcontroller.Pin + :param echo_pin: The pin on the microcontroller that's connected to the + ``Echo`` pin on the HC-SR04. + :type echo_pin: microcontroller.Pin + :param float timeout: Max seconds to wait for a response from the + sensor before assuming it isn't going to answer. Should *not* be + set to less than 0.05 seconds! + """ + self._timeout = timeout + self._trig = DigitalInOut(trigger_pin) + self._trig.direction = Direction.OUTPUT + + if _USE_PULSEIO: + self._echo = PulseIn(echo_pin) + self._echo.pause() + self._echo.clear() + else: + self._echo = DigitalInOut(echo_pin) + self._echo.direction = Direction.INPUT + + def __enter__(self) -> "HCSR04": + """Allows for use in context managers.""" + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + """Automatically de-initialize after a context manager.""" + self.deinit() + + def deinit(self) -> None: + """De-initialize the trigger and echo pins.""" + self._trig.deinit() + self._echo.deinit() + + @property + def distance(self) -> float: + """Return the distance measured by the sensor in cm. + + This is the function that will be called most often in user code. The + distance is calculated by timing a pulse from the sensor, indicating + how long between when the sensor sent out an ultrasonic signal and when + it bounced back and was received again. + + If no signal is received, we'll throw a RuntimeError exception. This means + either the sensor was moving too fast to be pointing in the right + direction to pick up the ultrasonic signal when it bounced back (less + likely), or the object off of which the signal bounced is too far away + for the sensor to handle. In my experience, the sensor can detect + objects over 460 cm away. + + :return: Distance in centimeters. + :rtype: float + """ + return self._dist_two_wire() # at this time we only support 2-wire meausre + + def _dist_two_wire(self) -> float: + if _USE_PULSEIO: + self._echo.clear() # Discard any previous pulse values + self._trig.value = True # Set trig high + time.sleep(0.00001) # 10 micro seconds 10/1000/1000 + self._trig.value = False # Set trig low + + pulselen = None + timestamp = time.monotonic() + if _USE_PULSEIO: + self._echo.resume() + while not self._echo: + # Wait for a pulse + if (time.monotonic() - timestamp) > self._timeout: + self._echo.pause() + raise RuntimeError("Timed out") + self._echo.pause() + pulselen = self._echo[0] + else: + # OK no hardware pulse support, we'll just do it by hand! + # hang out while the pin is low + while not self._echo.value: + if time.monotonic() - timestamp > self._timeout: + raise RuntimeError("Timed out") + timestamp = time.monotonic() + # track how long pin is high + while self._echo.value: + if time.monotonic() - timestamp > self._timeout: + raise RuntimeError("Timed out") + pulselen = time.monotonic() - timestamp + pulselen *= 1000000 # convert to us to match pulseio + if pulselen >= 65535: + raise RuntimeError("Timed out") + + # positive pulse time, in seconds, times 340 meters/sec, then + # divided by 2 gives meters. Multiply by 100 for cm + # 1/1000000 s/us * 340 m/s * 100 cm/m * 2 = 0.017 + return pulselen * 0.017 diff --git a/Octopus_CircuitPython_V1.0.0/Fan/code.py b/Octopus_CircuitPython_V1.0.0/Fan/code.py new file mode 100644 index 0000000..f9b3e12 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Fan/code.py @@ -0,0 +1,9 @@ +from Fan import * + +FANS1 = Fan(board.GP26) + +while True: + FANS1.set_fan() + + + diff --git a/Octopus_CircuitPython_V1.0.0/Fan/lib/Fan.py b/Octopus_CircuitPython_V1.0.0/Fan/lib/Fan.py new file mode 100644 index 0000000..1524787 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Fan/lib/Fan.py @@ -0,0 +1,12 @@ +import board +import pwmio + + +class Fan: + def __init__(self, pin): + self.pin = pin + self.motor = pwmio.PWMOut(self.pin, frequency=1000, duty_cycle=0) + + def set_fan(self, setFans = 100): + self.setFans = setFans + self.motor.duty_cycle = int(self.setFans * 655) diff --git a/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/__init__.mpy b/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/__init__.mpy new file mode 100644 index 0000000000000000000000000000000000000000..423847814cd3230e1589c27698c3315f11fcf3b0 GIT binary patch literal 42 vcmZ=}Ws+A=Vc=q5H%UxMOe-qQEQ!y}FUc>`kB`sH19IZ^3Mv@_lNlHQ=UWT? literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/motor.mpy b/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/motor.mpy new file mode 100644 index 0000000000000000000000000000000000000000..9c072308d5d45bc93533ca242568f6f8ca63d7d2 GIT binary patch literal 1115 zcmY*YT~FIq7(OS)OVTA^JE`Lp7*+!jO^Q=O)QJgcKwN}a`G|;wklH%NIfb+#cI^{7 zU+qNIG!1S4Vd_;c6Mn+}!L*Bxi?u(Zz3*Pz3#=DDexLXA(R1EY<6|@GPqS}g8j5RX z%Y5qg+SE9;sqL1-Q*->L%B1}AUjEUHsTUs1uFf{mrh%9s>^ihEFX!s5(#wJtL zciP?KDPG3GcgTcW4cD~Dk!d{-Q}E;sNFm-72hq(8G)e6pZ147H5hBjZ)3zN(wx-d6 zh|2HvEQ1~xf>o>ST0qV5>51JnqB+|CDlmGyl@6*3@AWZuxCL0av7}YCWmz_iGvazc z)iCl%77W8Bj%^rB&Tg#jHw^tjZSAlxXZIiO9z>u~!NRy++YV%?#$;T#F!okXD0RGV z%jM%XJ?R~3mVH_tDOO$^Nmq+_?nOMq4jL4^QiUR({&j(gqQZ?57*TSGUDPy z5$`XJL4dFDGD=mxkWspBp?F`&XOWm@-_6a$&^ z94NAJJplS3^oueoG(dZ0R2YEOq?8lcMpH$DOghZ{xl_5%^K9q-{9IwaR4DB%mI@0y zrM<%Z_w#62fA^Q3W5ayx?^*(W+@Ejt1e4G=dEifgBM%vRhOt3LRI;re^$p9nIs|Y= z;nsg=Lw2cu#csd)^y47IE8LZ_-iIzv0w|&7VHJO@;y<8=G<~VBK+#)$GAz3IFvuj8 zcvO~zj>_k~f;hBYzZ2GkJOExqPJu-RkO61i;y@Yn`YE@l-3t#-Yy5X{>S@oT>Jd?Q z>@HDl7fkw+kgmD_xvJT1sUDW1G*&F zBbi_i2<#3XmWYGA8pW~WE4Mibaq;z9(rS-al&fKBAPUi`bsag<6j9}U7A l)ZdJaqcmoH1gmi~+JGtYgGIuJAG|{H^)(EqN_6z#{{`R7Nsa&j literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/servo.mpy b/Octopus_CircuitPython_V1.0.0/Fan/lib/adafruit_motor/servo.mpy new file mode 100644 index 0000000000000000000000000000000000000000..8143ecbc9a66f950f3626d8b309ff7e49ec7e6ce GIT binary patch literal 1458 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 literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/LED/code.py b/Octopus_CircuitPython_V1.0.0/LED/code.py new file mode 100644 index 0000000..f66df7d --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/LED/code.py @@ -0,0 +1,12 @@ +import time +from LED import * + +led = LED(board.GP26) + +while 1: + led.set_led(0) + time.sleep(0.5) + led.set_led_bright() + time.sleep(0.5) + + diff --git a/Octopus_CircuitPython_V1.0.0/LED/lib/LED.py b/Octopus_CircuitPython_V1.0.0/LED/lib/LED.py new file mode 100644 index 0000000..8b1f25a --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/LED/lib/LED.py @@ -0,0 +1,19 @@ +import board +import pwmio + + +class LED: + def __init__(self, pin): + self.pin = pin + self.led = pwmio.PWMOut(self.pin, frequency=1000, duty_cycle=0) + + def set_led(self, ledStatus = 1): + self.ledStatus = ledStatus + if self.ledStatus == 1: + self.led.duty_cycle = int(65535) + else: + self.led.duty_cycle = int(0) + + def set_led_bright(self, ledBright = 100): + self.ledBright = ledBright + self.led.duty_cycle = int(self.ledBright * 655) diff --git a/Octopus_CircuitPython_V1.0.0/Light/code.py b/Octopus_CircuitPython_V1.0.0/Light/code.py new file mode 100644 index 0000000..d5a4197 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Light/code.py @@ -0,0 +1,9 @@ +import time +from Light import * + + +light = Light(A0) + +while 1: + print(light.get_lightlevel()) + time.sleep(0.5) \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Light/lib/Light.py b/Octopus_CircuitPython_V1.0.0/Light/lib/Light.py new file mode 100644 index 0000000..275e79e --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Light/lib/Light.py @@ -0,0 +1,11 @@ +import analogio +from board import * + + +class Light: + def __init__(self, pin): + self.pin = pin + self.pin = analogio.AnalogIn(self.pin) + + def get_lightlevel(self): + return self.pin.value \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Noise/code.py b/Octopus_CircuitPython_V1.0.0/Noise/code.py new file mode 100644 index 0000000..997048e --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Noise/code.py @@ -0,0 +1,8 @@ +import time +from Noise import * + +noise = Noise(A0) + +while 1: + print(noise.get_noise()) + time.sleep(0.5) \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Noise/lib/Noise.py b/Octopus_CircuitPython_V1.0.0/Noise/lib/Noise.py new file mode 100644 index 0000000..44da8f6 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Noise/lib/Noise.py @@ -0,0 +1,11 @@ +import analogio +from board import * + + +class Noise: + def __init__(self, pin): + self.pin = pin + self.pin = analogio.AnalogIn(self.pin) + + def get_noise(self): + return self.pin.value \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/OLED/code.py b/Octopus_CircuitPython_V1.0.0/OLED/code.py new file mode 100644 index 0000000..fdfe47f --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/OLED/code.py @@ -0,0 +1,27 @@ +from OLED import * +import time + + +oled = OLED(board.GP17, board.GP16) + + +oled.set_clear() +#oled.set_pixel() + +#oled.draw_line() +#oled.show() + +#oled.draw_circle() +#oled.show() + +#oled.draw_rectangle() +#oled.show() + + +#oled.set_show(0,0) +#oled.show() + + + + + diff --git a/Octopus_CircuitPython_V1.0.0/OLED/font5x8.bin b/Octopus_CircuitPython_V1.0.0/OLED/font5x8.bin new file mode 100644 index 0000000000000000000000000000000000000000..9a0563ba2dae1dc1d0b1b7ecb2e54e5113f3f540 GIT binary patch literal 1282 zcmXw3F>l*e5I$10{Ai>OqY^L;uo9&xs-z5NTtlD*ih5KiLlo?$F36^GP|Jyf4E0jD zLuHrZ%h+xn(jh<#Btfzi{RKsb0$utax^(lZ!Ki^k0DC8(cjWQCyLaDxJf5_~fW&+B z;F0H@JUH=8FY!#nObZw6zn4 zjUs@K#rYN*rdNEO1Pkd*mPTsc^S>BBnV1y6d{|k5ZDVrxgKR8=zjT7sOycL8lr6GBq8Oxc(z-zxK-+Mhj)*4rXS~& ziIRIf3is{<)s(5DfD56>lB^Iqhuks)D~cvu)Pulrf*`1)sS78HA_G{e%EsHbKTZTw zlnDe=j{JBBgjNr*o!F)XYfKV~Qm!*Ms#SyTIr-QCQL2j44XQ5ZR$?MQ)8#gIgE}JY zUR+!x!P96r0M^3K1K;57w-^vT*{$8Kxy9G79~at~dya(SQ8|v!{0h?Tm1E>=Me!NG zQT+6@upP(oXdA1Iw&N)J9H5{0Aor&|kopOq;s=<{>UZk1B#Qg=zDbmK zdviD#*lpi0pSOG5n!r!5UQIi_Ua!-^E_K{$R;>=w@cy&A8}p63ncDcr`u)39%^}no zG7qM{Js1o(9nLG~aK5r~I(={b-n7R#eXjlxWKa*xLD)u7-ocauKs%Vu#rfD;6hTA#%t}%>Prt4SAT-VpMl7?3aqa{k4 zVLqUXoV3*lk5&uG7F(QN1fXMU0CVMvP}T_ViUQXNMRL7Zt?B>6U*QUAP+Ey<&~IRl z27O3ULqd9nM;1YJW+XEbeBx1r&Tf+6&^W<-I2>-JvYgM$De7??`o|b>6`oo}i=6Vy zcbD&8n$56j?w(4gyY_Hz&$b7Xf&JT)gPo3tpAk|?lF}wg5R8L>?+*jcgW*2MVp8t! r=UA7qlM~h|w5qNAP4y=Jc^C##(KN7mCP`3|q#~?;uvP#Ug;>IW4$UpB literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/OLED/lib/OLED.py b/Octopus_CircuitPython_V1.0.0/OLED/lib/OLED.py new file mode 100644 index 0000000..5113053 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/OLED/lib/OLED.py @@ -0,0 +1,70 @@ +import board +import busio +import adafruit_ssd1306 +from digitalio import DigitalInOut + + +class OLED(): + def __init__(self, pinScl, pinSda): + self.pinScl = pinScl + self.pinSda = pinSda + i2c = busio.I2C(self.pinScl, self.pinSda) + pinReset = DigitalInOut(board.GP5) + self.display = adafruit_ssd1306.SSD1306_I2C( + 128, 64, i2c, addr=0x3C, reset=pinReset) + + def set_show(self, xStr, yStr, userStr): + self.xStr = xStr + self.yStr = yStr + self.userStr = userStr + self.userStrChange = str(userStr) + self.display.text(self.userStrChange, self.xStr, self.yStr, 1) + self.display.show() + + def set_clear(self): + self.display.fill(0) + self.display.show() + + def draw_rectangle(self, xRectangle, yRectangle, wRectangle, hRectangle, fill): + self.xRectangle = xRectangle + self.yRectangle = yRectangle + self.wRectangle = wRectangle + self.hRectangle = hRectangle + self.fill = fill + self.display.rect(self.xRectangle, self.yRectangle, + int(self.wRectangle), int(self.hRectangle), 1) + if self.fill == 1: + self.display.fill_rect(self.xRectangle, self.yRectangle, int( + self.wRectangle), int(self.hRectangle), 1) + else: + self.display.show() + self.display.show() + + def draw_circle(self, xCircle, yCircle, radius,fill=0): + self.xCircle = xCircle + self.yCircle = yCircle + self.radius = radius + self.fill = fill + if self.fill == 0: + self.display.circle(self.xCircle, self.yCircle, radius, 1) + self.display.show() + if self.fill == 1: + for i in range(self.radius,0,-1): + self.display.circle(self.xCircle, self.yCircle, i, 1) + self.display.show() + + def draw_line(self, x1Line = 0 , y1Line = 0, x2Line = 127 , y2Line = 63): + self.x1Line = x1Line + self.y1Line = y1Line + self.x2Line = x2Line + self.y2Line = y2Line + self.display.line(self.x1Line, self.y1Line, + self.x2Line, self.y2Line, 1) + self.display.show() + + def set_pixel(self, xPixel = 63, yPixel =31): + self.xPixel = xPixel + self.yPixel = yPixel + self.display.pixel(self.xPixel, self.yPixel, 1) + self.display.show() + diff --git a/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_framebuf.py b/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_framebuf.py new file mode 100644 index 0000000..b86c54a --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_framebuf.py @@ -0,0 +1,639 @@ +# SPDX-FileCopyrightText: 2018 Kattni Rembor, Melissa LeBlanc-Williams +# and Tony DiCola, for Adafruit Industries. +# Original file created by Damien P. George +# +# SPDX-License-Identifier: MIT + +""" +`adafruit_framebuf` +==================================================== + +CircuitPython pure-python framebuf module, based on the micropython framebuf module. + +Implementation Notes +-------------------- + +**Hardware:** + +* `Adafruit SSD1306 OLED displays `_ +* `Adafruit HT16K33 Matrix displays `_ + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://github.com/adafruit/circuitpython/releases + +""" + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_framebuf.git" + +import os +import struct + +# Framebuf format constants: +MVLSB = 0 # Single bit displays (like SSD1306 OLED) +RGB565 = 1 # 16-bit color displays +GS4_HMSB = 2 # Unimplemented! +MHMSB = 3 # Single bit displays like the Sharp Memory +RGB888 = 4 # Neopixels and Dotstars +GS2_HMSB = 5 # 2-bit color displays like the HT16K33 8x8 Matrix + + +class GS2HMSBFormat: + """GS2HMSBFormat""" + + @staticmethod + def set_pixel(framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y * framebuf.stride + x) >> 2 + pixel = framebuf.buf[index] + + shift = (x & 0b11) << 1 + mask = 0b11 << shift + color = (color & 0b11) << shift + + framebuf.buf[index] = color | (pixel & (~mask)) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y * framebuf.stride + x) >> 2 + pixel = framebuf.buf[index] + + shift = (x & 0b11) << 1 + return (pixel >> shift) & 0b11 + + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + bits = color & 0b11 + fill = (bits << 6) | (bits << 4) | (bits << 2) | (bits << 0) + else: + fill = 0x00 + + framebuf.buf = [fill for i in range(len(framebuf.buf))] + + @staticmethod + def rect(framebuf, x, y, width, height, color): + """Draw the outline of a rectangle at the given location, size and color.""" + # pylint: disable=too-many-arguments + for _x in range(x, x + width): + for _y in range(y, y + height): + if _x in [x, x + width] or _y in [y, y + height]: + GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) + + @staticmethod + def fill_rect(framebuf, x, y, width, height, color): + """Draw the outline and interior of a rectangle at the given location, size and color.""" + # pylint: disable=too-many-arguments + for _x in range(x, x + width): + for _y in range(y, y + height): + GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) + + +class MHMSBFormat: + """MHMSBFormat""" + + @staticmethod + def set_pixel(framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y * framebuf.stride + x) // 8 + offset = 7 - x & 0x07 + framebuf.buf[index] = (framebuf.buf[index] & ~(0x01 << offset)) | ( + (color != 0) << offset + ) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y * framebuf.stride + x) // 8 + offset = 7 - x & 0x07 + return (framebuf.buf[index] >> offset) & 0x01 + + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + fill = 0xFF + else: + fill = 0x00 + for i in range(len(framebuf.buf)): # pylint: disable=consider-using-enumerate + framebuf.buf[i] = fill + + @staticmethod + def fill_rect(framebuf, x, y, width, height, color): + """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws + both the outline and interior.""" + # pylint: disable=too-many-arguments + for _x in range(x, x + width): + offset = 7 - _x & 0x07 + for _y in range(y, y + height): + index = (_y * framebuf.stride + _x) // 8 + framebuf.buf[index] = (framebuf.buf[index] & ~(0x01 << offset)) | ( + (color != 0) << offset + ) + + +class MVLSBFormat: + """MVLSBFormat""" + + @staticmethod + def set_pixel(framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y >> 3) * framebuf.stride + x + offset = y & 0x07 + framebuf.buf[index] = (framebuf.buf[index] & ~(0x01 << offset)) | ( + (color != 0) << offset + ) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y >> 3) * framebuf.stride + x + offset = y & 0x07 + return (framebuf.buf[index] >> offset) & 0x01 + + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + fill = 0xFF + else: + fill = 0x00 + for i in range(len(framebuf.buf)): # pylint: disable=consider-using-enumerate + framebuf.buf[i] = fill + + @staticmethod + def fill_rect(framebuf, x, y, width, height, color): + """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws + both the outline and interior.""" + # pylint: disable=too-many-arguments + while height > 0: + index = (y >> 3) * framebuf.stride + x + offset = y & 0x07 + for w_w in range(width): + framebuf.buf[index + w_w] = ( + framebuf.buf[index + w_w] & ~(0x01 << offset) + ) | ((color != 0) << offset) + y += 1 + height -= 1 + + +class RGB565Format: + """ + This class implements the RGB565 format + It assumes a little-endian byte order in the frame buffer + """ + + @staticmethod + def color_to_rgb565(color): + """Convert a color in either tuple or 24 bit integer form to RGB565, + and return as two bytes""" + if isinstance(color, tuple): + hibyte = (color[0] & 0xF8) | (color[1] >> 5) + lobyte = ((color[1] << 5) & 0xE0) | (color[2] >> 3) + else: + hibyte = ((color >> 16) & 0xF8) | ((color >> 13) & 0x07) + lobyte = ((color >> 5) & 0xE0) | ((color >> 3) & 0x1F) + return bytes([lobyte, hibyte]) + + def set_pixel(self, framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y * framebuf.stride + x) * 2 + framebuf.buf[index : index + 2] = self.color_to_rgb565(color) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y * framebuf.stride + x) * 2 + lobyte, hibyte = framebuf.buf[index : index + 2] + r = hibyte & 0xF8 + g = ((hibyte & 0x07) << 5) | ((lobyte & 0xE0) >> 5) + b = (lobyte & 0x1F) << 3 + return (r << 16) | (g << 8) | b + + def fill(self, framebuf, color): + """completely fill/clear the buffer with a color""" + rgb565_color = self.color_to_rgb565(color) + for i in range(0, len(framebuf.buf), 2): + framebuf.buf[i : i + 2] = rgb565_color + + def fill_rect(self, framebuf, x, y, width, height, color): + """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws + both the outline and interior.""" + # pylint: disable=too-many-arguments + rgb565_color = self.color_to_rgb565(color) + for _y in range(2 * y, 2 * (y + height), 2): + offset2 = _y * framebuf.stride + for _x in range(2 * x, 2 * (x + width), 2): + index = offset2 + _x + framebuf.buf[index : index + 2] = rgb565_color + + +class RGB888Format: + """RGB888Format""" + + @staticmethod + def set_pixel(framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y * framebuf.stride + x) * 3 + if isinstance(color, tuple): + framebuf.buf[index : index + 3] = bytes(color) + else: + framebuf.buf[index : index + 3] = bytes( + ((color >> 16) & 255, (color >> 8) & 255, color & 255) + ) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y * framebuf.stride + x) * 3 + return ( + (framebuf.buf[index] << 16) + | (framebuf.buf[index + 1] << 8) + | framebuf.buf[index + 2] + ) + + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + fill = (color >> 16) & 255, (color >> 8) & 255, color & 255 + for i in range(0, len(framebuf.buf), 3): + framebuf.buf[i : i + 3] = bytes(fill) + + @staticmethod + def fill_rect(framebuf, x, y, width, height, color): + """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws + both the outline and interior.""" + # pylint: disable=too-many-arguments + fill = (color >> 16) & 255, (color >> 8) & 255, color & 255 + for _x in range(x, x + width): + for _y in range(y, y + height): + index = (_y * framebuf.stride + _x) * 3 + framebuf.buf[index : index + 3] = bytes(fill) + + +class FrameBuffer: + """FrameBuffer object. + + :param buf: An object with a buffer protocol which must be large enough to contain every + pixel defined by the width, height and format of the FrameBuffer. + :param width: The width of the FrameBuffer in pixel + :param height: The height of the FrameBuffer in pixel + :param buf_format: Specifies the type of pixel used in the FrameBuffer; permissible values + are listed under Constants below. These set the number of bits used to + encode a color value and the layout of these bits in ``buf``. Where a + color value c is passed to a method, c is a small integer with an encoding + that is dependent on the format of the FrameBuffer. + :param stride: The number of pixels between each horizontal line of pixels in the + FrameBuffer. This defaults to ``width`` but may need adjustments when + implementing a FrameBuffer within another larger FrameBuffer or screen. The + ``buf`` size must accommodate an increased step size. + + """ + + def __init__(self, buf, width, height, buf_format=MVLSB, stride=None): + # pylint: disable=too-many-arguments + self.buf = buf + self.width = width + self.height = height + self.stride = stride + self._font = None + if self.stride is None: + self.stride = width + if buf_format == MVLSB: + self.format = MVLSBFormat() + elif buf_format == MHMSB: + self.format = MHMSBFormat() + elif buf_format == RGB888: + self.format = RGB888Format() + elif buf_format == RGB565: + self.format = RGB565Format() + elif buf_format == GS2_HMSB: + self.format = GS2HMSBFormat() + else: + raise ValueError("invalid format") + self._rotation = 0 + + @property + def rotation(self): + """The rotation setting of the display, can be one of (0, 1, 2, 3)""" + return self._rotation + + @rotation.setter + def rotation(self, val): + if not val in (0, 1, 2, 3): + raise RuntimeError("Bad rotation setting") + self._rotation = val + + def fill(self, color): + """Fill the entire FrameBuffer with the specified color.""" + self.format.fill(self, color) + + def fill_rect(self, x, y, width, height, color): + """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws + both the outline and interior.""" + # pylint: disable=too-many-arguments, too-many-boolean-expressions + self.rect(x, y, width, height, color, fill=True) + + def pixel(self, x, y, color=None): + """If ``color`` is not given, get the color value of the specified pixel. If ``color`` is + given, set the specified pixel to the given color.""" + if self.rotation == 1: + x, y = y, x + x = self.width - x - 1 + if self.rotation == 2: + x = self.width - x - 1 + y = self.height - y - 1 + if self.rotation == 3: + x, y = y, x + y = self.height - y - 1 + + if x < 0 or x >= self.width or y < 0 or y >= self.height: + return None + if color is None: + return self.format.get_pixel(self, x, y) + self.format.set_pixel(self, x, y, color) + return None + + def hline(self, x, y, width, color): + """Draw a horizontal line up to a given length.""" + self.rect(x, y, width, 1, color, fill=True) + + def vline(self, x, y, height, color): + """Draw a vertical line up to a given length.""" + self.rect(x, y, 1, height, color, fill=True) + + def circle(self, center_x, center_y, radius, color): + """Draw a circle at the given midpoint location, radius and color. + The ```circle``` method draws only a 1 pixel outline.""" + x = radius - 1 + y = 0 + d_x = 1 + d_y = 1 + err = d_x - (radius << 1) + while x >= y: + self.pixel(center_x + x, center_y + y, color) + self.pixel(center_x + y, center_y + x, color) + self.pixel(center_x - y, center_y + x, color) + self.pixel(center_x - x, center_y + y, color) + self.pixel(center_x - x, center_y - y, color) + self.pixel(center_x - y, center_y - x, color) + self.pixel(center_x + y, center_y - x, color) + self.pixel(center_x + x, center_y - y, color) + if err <= 0: + y += 1 + err += d_y + d_y += 2 + if err > 0: + x -= 1 + d_x += 2 + err += d_x - (radius << 1) + + def rect(self, x, y, width, height, color, *, fill=False): + """Draw a rectangle at the given location, size and color. The ```rect``` method draws only + a 1 pixel outline.""" + # pylint: disable=too-many-arguments + if self.rotation == 1: + x, y = y, x + width, height = height, width + x = self.width - x - width + if self.rotation == 2: + x = self.width - x - width + y = self.height - y - height + if self.rotation == 3: + x, y = y, x + width, height = height, width + y = self.height - y - height + + # pylint: disable=too-many-boolean-expressions + if ( + width < 1 + or height < 1 + or (x + width) <= 0 + or (y + height) <= 0 + or y >= self.height + or x >= self.width + ): + return + x_end = min(self.width - 1, x + width - 1) + y_end = min(self.height - 1, y + height - 1) + x = max(x, 0) + y = max(y, 0) + if fill: + self.format.fill_rect(self, x, y, x_end - x + 1, y_end - y + 1, color) + else: + self.format.fill_rect(self, x, y, x_end - x + 1, 1, color) + self.format.fill_rect(self, x, y, 1, y_end - y + 1, color) + self.format.fill_rect(self, x, y_end, x_end - x + 1, 1, color) + self.format.fill_rect(self, x_end, y, 1, y_end - y + 1, color) + + def line(self, x_0, y_0, x_1, y_1, color): + # pylint: disable=too-many-arguments + """Bresenham's line algorithm""" + d_x = abs(x_1 - x_0) + d_y = abs(y_1 - y_0) + x, y = x_0, y_0 + s_x = -1 if x_0 > x_1 else 1 + s_y = -1 if y_0 > y_1 else 1 + if d_x > d_y: + err = d_x / 2.0 + while x != x_1: + self.pixel(x, y, color) + err -= d_y + if err < 0: + y += s_y + err += d_x + x += s_x + else: + err = d_y / 2.0 + while y != y_1: + self.pixel(x, y, color) + err -= d_x + if err < 0: + x += s_x + err += d_y + y += s_y + self.pixel(x, y, color) + + def blit(self): + """blit is not yet implemented""" + raise NotImplementedError() + + def scroll(self, delta_x, delta_y): + """shifts framebuf in x and y direction""" + if delta_x < 0: + shift_x = 0 + xend = self.width + delta_x + dt_x = 1 + else: + shift_x = self.width - 1 + xend = delta_x - 1 + dt_x = -1 + if delta_y < 0: + y = 0 + yend = self.height + delta_y + dt_y = 1 + else: + y = self.height - 1 + yend = delta_y - 1 + dt_y = -1 + while y != yend: + x = shift_x + while x != xend: + self.format.set_pixel( + self, x, y, self.format.get_pixel(self, x - delta_x, y - delta_y) + ) + x += dt_x + y += dt_y + + # pylint: disable=too-many-arguments + def text(self, string, x, y, color, *, font_name="font5x8.bin", size=1): + """Place text on the screen in variables sizes. Breaks on \n to next line. + + Does not break on line going off screen. + """ + # determine our effective width/height, taking rotation into account + frame_width = self.width + frame_height = self.height + if self.rotation in (1, 3): + frame_width, frame_height = frame_height, frame_width + + for chunk in string.split("\n"): + if not self._font or self._font.font_name != font_name: + # load the font! + self._font = BitmapFont(font_name) + width = self._font.font_width + height = self._font.font_height + for i, char in enumerate(chunk): + char_x = x + (i * (width + 1)) * size + if ( + char_x + (width * size) > 0 + and char_x < frame_width + and y + (height * size) > 0 + and y < frame_height + ): + self._font.draw_char(char, char_x, y, self, color, size=size) + y += height * size + + # pylint: enable=too-many-arguments + + def image(self, img): + """Set buffer to value of Python Imaging Library image. The image should + be in 1 bit mode and a size equal to the display size.""" + # determine our effective width/height, taking rotation into account + width = self.width + height = self.height + if self.rotation in (1, 3): + width, height = height, width + + if isinstance(self.format, (RGB565Format, RGB888Format)) and img.mode != "RGB": + raise ValueError("Image must be in mode RGB.") + if isinstance(self.format, (MHMSBFormat, MVLSBFormat)) and img.mode != "1": + raise ValueError("Image must be in mode 1.") + + imwidth, imheight = img.size + if imwidth != width or imheight != height: + raise ValueError( + f"Image must be same dimensions as display ({width}x{height})." + ) + # Grab all the pixels from the image, faster than getpixel. + pixels = img.load() + # Clear buffer + for i in range(len(self.buf)): # pylint: disable=consider-using-enumerate + self.buf[i] = 0 + # Iterate through the pixels + for x in range(width): # yes this double loop is slow, + for y in range(height): # but these displays are small! + if img.mode == "RGB": + self.pixel(x, y, pixels[(x, y)]) + elif pixels[(x, y)]: + self.pixel(x, y, 1) # only write if pixel is true + + +# MicroPython basic bitmap font renderer. +# Author: Tony DiCola +# License: MIT License (https://opensource.org/licenses/MIT) +class BitmapFont: + """A helper class to read binary font tiles and 'seek' through them as a + file to display in a framebuffer. We use file access so we dont waste 1KB + of RAM on a font!""" + + def __init__(self, font_name="font5x8.bin"): + # Specify the drawing area width and height, and the pixel function to + # call when drawing pixels (should take an x and y param at least). + # Optionally specify font_name to override the font file to use (default + # is font5x8.bin). The font format is a binary file with the following + # format: + # - 1 unsigned byte: font character width in pixels + # - 1 unsigned byte: font character height in pixels + # - x bytes: font data, in ASCII order covering all 255 characters. + # Each character should have a byte for each pixel column of + # data (i.e. a 5x8 font has 5 bytes per character). + self.font_name = font_name + + # Open the font file and grab the character width and height values. + # Note that only fonts up to 8 pixels tall are currently supported. + try: + self._font = open( # pylint: disable=consider-using-with + self.font_name, "rb" + ) + self.font_width, self.font_height = struct.unpack("BB", self._font.read(2)) + # simple font file validation check based on expected file size + if 2 + 256 * self.font_width != os.stat(font_name)[6]: + raise RuntimeError("Invalid font file: " + font_name) + except OSError: + print("Could not find font file", font_name) + raise + except OverflowError: + # os.stat can throw this on boards without long int support + # just hope the font file is valid and press on + pass + + def deinit(self): + """Close the font file as cleanup.""" + self._font.close() + + def __enter__(self): + """Initialize/open the font file""" + self.__init__() + return self + + def __exit__(self, exception_type, exception_value, traceback): + """cleanup on exit""" + self.deinit() + + def draw_char( + self, char, x, y, framebuffer, color, size=1 + ): # pylint: disable=too-many-arguments + """Draw one character at position (x,y) to a framebuffer in a given color""" + size = max(size, 1) + # Don't draw the character if it will be clipped off the visible area. + # if x < -self.font_width or x >= framebuffer.width or \ + # y < -self.font_height or y >= framebuffer.height: + # return + # Go through each column of the character. + for char_x in range(self.font_width): + # Grab the byte for the current column of font data. + self._font.seek(2 + (ord(char) * self.font_width) + char_x) + try: + line = struct.unpack("B", self._font.read(1))[0] + except RuntimeError: + continue # maybe character isnt there? go to next + # Go through each row in the column byte. + for char_y in range(self.font_height): + # Draw a pixel for each bit that's flipped on. + if (line >> char_y) & 0x1: + framebuffer.fill_rect( + x + char_x * size, y + char_y * size, size, size, color + ) + + def width(self, text): + """Return the pixel width of the specified text message.""" + return len(text) * (self.font_width + 1) + + +class FrameBuffer1(FrameBuffer): # pylint: disable=abstract-method + """FrameBuffer1 object. Inherits from FrameBuffer.""" diff --git a/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_ssd1306.py b/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_ssd1306.py new file mode 100644 index 0000000..8e0654a --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/OLED/lib/adafruit_ssd1306.py @@ -0,0 +1,352 @@ +# SPDX-FileCopyrightText: 2017 Michael McWethy for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +`adafruit_ssd1306` +==================================================== + +MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +* Author(s): Tony DiCola, Michael McWethy +""" + +import time + +from micropython import const +from adafruit_bus_device import i2c_device, spi_device + +try: + # MicroPython framebuf import + import framebuf + + _FRAMEBUF_FORMAT = framebuf.MONO_VLSB +except ImportError: + # CircuitPython framebuf import + import adafruit_framebuf as framebuf + + _FRAMEBUF_FORMAT = framebuf.MVLSB + +try: + # Used only for typing + from typing import Optional + import busio + import digitalio +except ImportError: + pass + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SSD1306.git" + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xA4) +SET_NORM_INV = const(0xA6) +SET_DISP = const(0xAE) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xA0) +SET_MUX_RATIO = const(0xA8) +SET_IREF_SELECT = const(0xAD) +SET_COM_OUT_DIR = const(0xC0) +SET_DISP_OFFSET = const(0xD3) +SET_COM_PIN_CFG = const(0xDA) +SET_DISP_CLK_DIV = const(0xD5) +SET_PRECHARGE = const(0xD9) +SET_VCOM_DESEL = const(0xDB) +SET_CHARGE_PUMP = const(0x8D) + + +class _SSD1306(framebuf.FrameBuffer): + """Base class for SSD1306 display driver""" + + # pylint: disable-msg=too-many-arguments + def __init__( + self, + buffer: memoryview, + width: int, + height: int, + *, + external_vcc: bool, + reset: Optional[digitalio.DigitalInOut], + page_addressing: bool + ): + super().__init__(buffer, width, height, _FRAMEBUF_FORMAT) + self.width = width + self.height = height + self.external_vcc = external_vcc + # reset may be None if not needed + self.reset_pin = reset + self.page_addressing = page_addressing + if self.reset_pin: + self.reset_pin.switch_to_output(value=0) + self.pages = self.height // 8 + # Note the subclass must initialize self.framebuf to a framebuffer. + # This is necessary because the underlying data buffer is different + # between I2C and SPI implementations (I2C needs an extra byte). + self._power = False + # Parameters for efficient Page Addressing Mode (typical of U8Glib libraries) + # Important as not all screens appear to support Horizontal Addressing Mode + if self.page_addressing: + self.pagebuffer = bytearray(width + 1) # type: Optional[bytearray] + self.pagebuffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1 + self.page_column_start = bytearray(2) # type: Optional[bytearray] + self.page_column_start[0] = self.width % 32 + self.page_column_start[1] = 0x10 + self.width // 32 + else: + self.pagebuffer = None + self.page_column_start = None + # Let's get moving! + self.poweron() + self.init_display() + + @property + def power(self) -> bool: + """True if the display is currently powered on, otherwise False""" + return self._power + + def init_display(self) -> None: + """Base class to initialize display""" + # The various screen sizes available with the ssd1306 OLED driver + # chip require differing configuration values for the display clock + # div and com pin, which are listed below for reference and future + # compatibility: + # w, h: DISP_CLK_DIV COM_PIN_CFG + # 128, 64: 0x80 0x12 + # 128, 32: 0x80 0x02 + # 96, 16: 0x60 0x02 + # 64, 48: 0x80 0x12 + # 64, 32: 0x80 0x12 + for cmd in ( + SET_DISP, # off + # address setting + SET_MEM_ADDR, + 0x10 # Page Addressing Mode + if self.page_addressing + else 0x00, # Horizontal Addressing Mode + # resolution and layout + SET_DISP_START_LINE, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc # n.b. specs for ssd1306 64x32 oled screens imply this should be 0x40 + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + SET_IREF_SELECT, + 0x30, # enable internal IREF during display on + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, # display on + ): + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self) -> None: + """Turn off the display (nothing visible)""" + self.write_cmd(SET_DISP) + self._power = False + + def contrast(self, contrast: int) -> None: + """Adjust the contrast""" + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert: bool) -> None: + """Invert all pixels on the display""" + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def rotate(self, rotate: bool) -> None: + """Rotate the display 0 or 180 degrees""" + self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) + self.write_cmd(SET_SEG_REMAP | (rotate & 1)) + # com output (vertical mirror) is changed immediately + # you need to call show() for the seg remap to be visible + + def write_framebuf(self) -> None: + """Derived class must implement this""" + raise NotImplementedError + + def write_cmd(self, cmd: int) -> None: + """Derived class must implement this""" + raise NotImplementedError + + def poweron(self) -> None: + "Reset device and turn on the display." + if self.reset_pin: + self.reset_pin.value = 1 + time.sleep(0.001) + self.reset_pin.value = 0 + time.sleep(0.010) + self.reset_pin.value = 1 + time.sleep(0.010) + self.write_cmd(SET_DISP | 0x01) + self._power = True + + def show(self) -> None: + """Update the display""" + if not self.page_addressing: + xpos0 = 0 + xpos1 = self.width - 1 + if self.width != 128: + # narrow displays use centered columns + col_offset = (128 - self.width) // 2 + xpos0 += col_offset + xpos1 += col_offset + self.write_cmd(SET_COL_ADDR) + self.write_cmd(xpos0) + self.write_cmd(xpos1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_framebuf() + + +class SSD1306_I2C(_SSD1306): + """ + I2C class for SSD1306 + + :param width: the width of the physical screen in pixels, + :param height: the height of the physical screen in pixels, + :param i2c: the I2C peripheral to use, + :param addr: the 8-bit bus address of the device, + :param external_vcc: whether external high-voltage source is connected. + :param reset: if needed, DigitalInOut designating reset pin + """ + + def __init__( + self, + width: int, + height: int, + i2c: busio.I2C, + *, + addr: int = 0x3C, + external_vcc: bool = False, + reset: Optional[digitalio.DigitalInOut] = None, + page_addressing: bool = False + ): + self.i2c_device = i2c_device.I2CDevice(i2c, addr) + self.addr = addr + self.page_addressing = page_addressing + self.temp = bytearray(2) + # Add an extra byte to the data buffer to hold an I2C data/command byte + # to use hardware-compatible I2C transactions. A memoryview of the + # buffer is used to mask this byte from the framebuffer operations + # (without a major memory hit as memoryview doesn't copy to a separate + # buffer). + self.buffer = bytearray(((height // 8) * width) + 1) + self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1 + super().__init__( + memoryview(self.buffer)[1:], + width, + height, + external_vcc=external_vcc, + reset=reset, + page_addressing=self.page_addressing, + ) + + def write_cmd(self, cmd: int) -> None: + """Send a command to the I2C device""" + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + with self.i2c_device: + self.i2c_device.write(self.temp) + + def write_framebuf(self) -> None: + """Blast out the frame buffer using a single I2C transaction to support + hardware I2C interfaces.""" + if self.page_addressing: + for page in range(self.pages): + self.write_cmd(0xB0 + page) + self.write_cmd(self.page_column_start[0]) + self.write_cmd(self.page_column_start[1]) + self.pagebuffer[1:] = self.buffer[ + 1 + self.width * page : 1 + self.width * (page + 1) + ] + with self.i2c_device: + self.i2c_device.write(self.pagebuffer) + else: + with self.i2c_device: + self.i2c_device.write(self.buffer) + + +# pylint: disable-msg=too-many-arguments +class SSD1306_SPI(_SSD1306): + """ + SPI class for SSD1306 + + :param width: the width of the physical screen in pixels, + :param height: the height of the physical screen in pixels, + :param spi: the SPI peripheral to use, + :param dc: the data/command pin to use (often labeled "D/C"), + :param reset: the reset pin to use, + :param cs: the chip-select pin to use (sometimes labeled "SS"). + """ + + # pylint: disable=no-member + # Disable should be reconsidered when refactor can be tested. + def __init__( + self, + width: int, + height: int, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + reset: Optional[digitalio.DigitalInOut], + cs: digitalio.DigitalInOut, + *, + external_vcc: bool = False, + baudrate: int = 8000000, + polarity: int = 0, + phase: int = 0, + page_addressing: bool = False + ): + self.page_addressing = page_addressing + if self.page_addressing: + raise NotImplementedError( + "Page addressing mode with SPI has not yet been implemented." + ) + + self.rate = 10 * 1024 * 1024 + dc.switch_to_output(value=0) + self.spi_device = spi_device.SPIDevice( + spi, cs, baudrate=baudrate, polarity=polarity, phase=phase + ) + self.dc_pin = dc + self.buffer = bytearray((height // 8) * width) + super().__init__( + memoryview(self.buffer), + width, + height, + external_vcc=external_vcc, + reset=reset, + page_addressing=self.page_addressing, + ) + + def write_cmd(self, cmd: int) -> None: + """Send a command to the SPI device""" + self.dc_pin.value = 0 + with self.spi_device as spi: + spi.write(bytearray([cmd])) + + def write_framebuf(self) -> None: + """write to the frame buffer via SPI""" + self.dc_pin.value = 1 + with self.spi_device as spi: + spi.write(self.buffer) diff --git a/Octopus_CircuitPython_V1.0.0/README.md b/Octopus_CircuitPython_V1.0.0/README.md new file mode 100644 index 0000000..d5dd5f1 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/README.md @@ -0,0 +1,2 @@ +# octpus_circuitpython +elecfreaks/Octopus_CircuitPython diff --git a/Octopus_CircuitPython_V1.0.0/Servo/code.py b/Octopus_CircuitPython_V1.0.0/Servo/code.py new file mode 100644 index 0000000..f3de528 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Servo/code.py @@ -0,0 +1,9 @@ +import time +from Servo import * + +s = Servo(board.GP27) +while True: + s.set_servo(180) + time.sleep(1) + s.set_servo(0) + time.sleep(1) \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Servo/lib/Servo.py b/Octopus_CircuitPython_V1.0.0/Servo/lib/Servo.py new file mode 100644 index 0000000..3d34b38 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Servo/lib/Servo.py @@ -0,0 +1,14 @@ +import board +import pwmio +from adafruit_motor import servo + + +class Servo: + def __init__(self, pin): + self.pin = pin + self.pwm = pwmio.PWMOut(self.pin, duty_cycle=2 ** 15, frequency=50) + + def set_servo(self, angle = 90): + setServo = servo.Servo(self.pwm) + self.angle = angle + setServo.angle = self.angle diff --git a/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/__init__.mpy b/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/__init__.mpy new file mode 100644 index 0000000000000000000000000000000000000000..423847814cd3230e1589c27698c3315f11fcf3b0 GIT binary patch literal 42 vcmZ=}Ws+A=Vc=q5H%UxMOe-qQEQ!y}FUc>`kB`sH19IZ^3Mv@_lNlHQ=UWT? literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/motor.mpy b/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/motor.mpy new file mode 100644 index 0000000000000000000000000000000000000000..9c072308d5d45bc93533ca242568f6f8ca63d7d2 GIT binary patch literal 1115 zcmY*YT~FIq7(OS)OVTA^JE`Lp7*+!jO^Q=O)QJgcKwN}a`G|;wklH%NIfb+#cI^{7 zU+qNIG!1S4Vd_;c6Mn+}!L*Bxi?u(Zz3*Pz3#=DDexLXA(R1EY<6|@GPqS}g8j5RX z%Y5qg+SE9;sqL1-Q*->L%B1}AUjEUHsTUs1uFf{mrh%9s>^ihEFX!s5(#wJtL zciP?KDPG3GcgTcW4cD~Dk!d{-Q}E;sNFm-72hq(8G)e6pZ147H5hBjZ)3zN(wx-d6 zh|2HvEQ1~xf>o>ST0qV5>51JnqB+|CDlmGyl@6*3@AWZuxCL0av7}YCWmz_iGvazc z)iCl%77W8Bj%^rB&Tg#jHw^tjZSAlxXZIiO9z>u~!NRy++YV%?#$;T#F!okXD0RGV z%jM%XJ?R~3mVH_tDOO$^Nmq+_?nOMq4jL4^QiUR({&j(gqQZ?57*TSGUDPy z5$`XJL4dFDGD=mxkWspBp?F`&XOWm@-_6a$&^ z94NAJJplS3^oueoG(dZ0R2YEOq?8lcMpH$DOghZ{xl_5%^K9q-{9IwaR4DB%mI@0y zrM<%Z_w#62fA^Q3W5ayx?^*(W+@Ejt1e4G=dEifgBM%vRhOt3LRI;re^$p9nIs|Y= z;nsg=Lw2cu#csd)^y47IE8LZ_-iIzv0w|&7VHJO@;y<8=G<~VBK+#)$GAz3IFvuj8 zcvO~zj>_k~f;hBYzZ2GkJOExqPJu-RkO61i;y@Yn`YE@l-3t#-Yy5X{>S@oT>Jd?Q z>@HDl7fkw+kgmD_xvJT1sUDW1G*&F zBbi_i2<#3XmWYGA8pW~WE4Mibaq;z9(rS-al&fKBAPUi`bsag<6j9}U7A l)ZdJaqcmoH1gmi~+JGtYgGIuJAG|{H^)(EqN_6z#{{`R7Nsa&j literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/servo.mpy b/Octopus_CircuitPython_V1.0.0/Servo/lib/adafruit_motor/servo.mpy new file mode 100644 index 0000000000000000000000000000000000000000..8143ecbc9a66f950f3626d8b309ff7e49ec7e6ce GIT binary patch literal 1458 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 literal 0 HcmV?d00001 diff --git a/Octopus_CircuitPython_V1.0.0/Trimpot/code.py b/Octopus_CircuitPython_V1.0.0/Trimpot/code.py new file mode 100644 index 0000000..bfef494 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Trimpot/code.py @@ -0,0 +1,11 @@ +from Trimpot import * +import time + + +trimpot = Trimpot(A0) + + +while 1: + print(trimpot.get_trimpot()) + time.sleep(0.5) + diff --git a/Octopus_CircuitPython_V1.0.0/Trimpot/lib/Trimpot.py b/Octopus_CircuitPython_V1.0.0/Trimpot/lib/Trimpot.py new file mode 100644 index 0000000..78a37a3 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Trimpot/lib/Trimpot.py @@ -0,0 +1,11 @@ +import analogio +from board import * + + +class Trimpot: + def __init__(self, pin): + self.pin = pin + self.pin = analogio.AnalogIn(self.pin) + + def get_trimpot(self): + return self.pin.value \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Waterlevel/code.py b/Octopus_CircuitPython_V1.0.0/Waterlevel/code.py new file mode 100644 index 0000000..4669158 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Waterlevel/code.py @@ -0,0 +1,9 @@ +import time +from Waterlevel import * + + +waterlevel = Waterlevel(A0) + +while 1: + print(waterlevel.get_waterlevel()) + time.sleep(0.5) \ No newline at end of file diff --git a/Octopus_CircuitPython_V1.0.0/Waterlevel/lib/Waterlevel.py b/Octopus_CircuitPython_V1.0.0/Waterlevel/lib/Waterlevel.py new file mode 100644 index 0000000..2a3aa36 --- /dev/null +++ b/Octopus_CircuitPython_V1.0.0/Waterlevel/lib/Waterlevel.py @@ -0,0 +1,11 @@ +import analogio +from board import * + + +class Waterlevel: + def __init__(self, pin): + self.pin = pin + self.pin = analogio.AnalogIn(self.pin) + + def get_waterlevel(self): + return self.pin.value