From 4b0aa8714c03221c0c0325252870c08815b297cc Mon Sep 17 00:00:00 2001 From: Kitki30 Date: Sun, 18 Aug 2024 11:14:09 +0200 Subject: [PATCH] Initial commit Signed-off-by: Kitki30 --- .github/ISSUE_TEMPLATE/bug-report.yml | 100 ++ .github/workflows/main.yml | 179 ++++ .gitignore | 25 + .pre-commit-config.yaml | 11 + LICENSE | 21 + README.md | 8 + download_list_guide.md | 194 ++++ guide.md | 4 + pico_w/Gameberry/boot_config.json | 10 + .../Gameberry/default/settings_default.json | 17 + pico_w/Gameberry/device_config.json | 4 + pico_w/Gameberry/game/game.py | 74 ++ pico_w/Gameberry/game/game_info.json | 10 + pico_w/Gameberry/game/save_default.json | 3 + pico_w/Gameberry/gameberry.py | 861 ++++++++++++++++++ pico_w/Gameberry/main.py | 150 +++ pico_w/Gameberry/modules/RGB1602.py | 158 ++++ pico_w/Gameberry/modules/basicThread.py | 58 ++ pico_w/Gameberry/modules/battery.py | 93 ++ pico_w/Gameberry/modules/blinker.py | 11 + pico_w/Gameberry/modules/characterSets.py | 89 ++ pico_w/Gameberry/modules/customExceptions.py | 44 + pico_w/Gameberry/modules/files.py | 25 + pico_w/Gameberry/modules/gameSystemMenu.py | 69 ++ pico_w/Gameberry/modules/ina219.py | 79 ++ pico_w/Gameberry/modules/json.py | 13 + pico_w/Gameberry/modules/math.py | 5 + pico_w/Gameberry/modules/ntp.py | 10 + pico_w/Gameberry/modules/requests.py | 13 + pico_w/Gameberry/modules/saveDataManager.py | 69 ++ pico_w/Gameberry/modules/sd.py | 68 ++ pico_w/Gameberry/modules/sdcard.py | 241 +++++ pico_w/Gameberry/modules/time.py | 16 + pico_w/Gameberry/modules/translations.py | 31 + pico_w/Gameberry/plugins/octolib.py | 269 ++++++ pico_w/Gameberry/plugins/octoprint.py | 207 +++++ pico_w/Gameberry/translations/en.json | 39 + pico_w/Gameberry/translations/pl.json | 39 + pico_w/Gameberry/voltage_meter_mode.py | 15 + pico_w/Gameberry/webSetup/webSetup.py | 68 ++ pico_w/README.MD | 28 + pico_w/download_list.txt | 115 +++ pico_w/install.py | 300 ++++++ 43 files changed, 3843 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 download_list_guide.md create mode 100644 guide.md create mode 100644 pico_w/Gameberry/boot_config.json create mode 100644 pico_w/Gameberry/default/settings_default.json create mode 100644 pico_w/Gameberry/device_config.json create mode 100644 pico_w/Gameberry/game/game.py create mode 100644 pico_w/Gameberry/game/game_info.json create mode 100644 pico_w/Gameberry/game/save_default.json create mode 100644 pico_w/Gameberry/gameberry.py create mode 100644 pico_w/Gameberry/main.py create mode 100644 pico_w/Gameberry/modules/RGB1602.py create mode 100644 pico_w/Gameberry/modules/basicThread.py create mode 100644 pico_w/Gameberry/modules/battery.py create mode 100644 pico_w/Gameberry/modules/blinker.py create mode 100644 pico_w/Gameberry/modules/characterSets.py create mode 100644 pico_w/Gameberry/modules/customExceptions.py create mode 100644 pico_w/Gameberry/modules/files.py create mode 100644 pico_w/Gameberry/modules/gameSystemMenu.py create mode 100644 pico_w/Gameberry/modules/ina219.py create mode 100644 pico_w/Gameberry/modules/json.py create mode 100644 pico_w/Gameberry/modules/math.py create mode 100644 pico_w/Gameberry/modules/ntp.py create mode 100644 pico_w/Gameberry/modules/requests.py create mode 100644 pico_w/Gameberry/modules/saveDataManager.py create mode 100644 pico_w/Gameberry/modules/sd.py create mode 100644 pico_w/Gameberry/modules/sdcard.py create mode 100644 pico_w/Gameberry/modules/time.py create mode 100644 pico_w/Gameberry/modules/translations.py create mode 100644 pico_w/Gameberry/plugins/octolib.py create mode 100644 pico_w/Gameberry/plugins/octoprint.py create mode 100644 pico_w/Gameberry/translations/en.json create mode 100644 pico_w/Gameberry/translations/pl.json create mode 100644 pico_w/Gameberry/voltage_meter_mode.py create mode 100644 pico_w/Gameberry/webSetup/webSetup.py create mode 100644 pico_w/README.MD create mode 100644 pico_w/download_list.txt create mode 100644 pico_w/install.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..cdd8798 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,100 @@ +name: Bug report +description: Report a bug. +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Report bugs here! + - type: dropdown + id: microcontroller-dropdows + attributes: + label: Microcontroller + description: | + Please select microcontroller you are using + options: + - "Raspberry Pi Pico W" + multiple: false + validations: + required: true + - type: input + id: gameberry-version + attributes: + label: GameBerry version + description: | + To check the version: + + 1. Turn on microcontroller + 2. Version will be shown on boot + + placeholder: | + v0.8 + validations: + required: true + + - type: input + id: micropython-version + attributes: + label: Micropython version + description: | + Please type the version of micropython that is installed on your microcontroller. + placeholder: | + MicroPython v1.23.0 on 2024-05-31; darwin [GCC 4.2.1] version + validations: + required: true + + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps to reproduce + description: | + Please enter steps to reproduce the bug. + + If bug happens when you launch a game/plugin, please type Github Repo with code of Game/Plugin + + placeholder: | + 1. Turn on microcontroller + 2. Press Home button 20 times. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behaviour + description: | + What should it do? + placeholder: | + Expected to launch easter egg. + - type: textarea + id: what-happened + attributes: + label: Observed behaviour / Error log + description: | + What happened? Provide error log if you can. + placeholder: | + My gameberry exploded 😮! + validations: + required: true + - type: checkboxes + id: additional-hardware + attributes: + label: Additional hardware used + description: You can select more than one. + options: + - label: Battery (Please provide type of battery, charger, capacity, and battery name in additional info) + - label: INA219 (Measures battery voltage, current and power) + - label: SD Card reader (Provide sd card capacity if sd card is used) + - type: textarea + id: additional-info + attributes: + label: Additioal information + description: | + Anything else? Type additional information here! + placeholder: | + I used 32GB FAT32 formatted SD card + validations: + required: false + - type: markdown + attributes: + value: | + Thanks for taking the time to help improve Gameberry. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..092fd4b --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,179 @@ +name: Release bot + +on: + push: + branches: + - main # Trigger on push to the main branch + +jobs: + minify: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5.1.1 + + - name: Install dependencies + run: | + pip install python-minifier + + - name: Minify Python files + run: | + python -c " + import os + import python_minifier + + def handle_folder(path): + for file in os.listdir(path): + full_path = os.path.join(path, file) + print('Scan:', file) + if os.path.isdir(full_path): + print('called with:', file) + handle_folder(full_path) + elif file.endswith('.py'): + print('Minify:', file) + with open(full_path, 'r') as f: + content = f.read() + minified_content = python_minifier.minify(content) + with open(full_path, 'w') as f: + f.write(minified_content) + scan_path = './pico_w/Gameberry/' + handle_folder(scan_path) + " + + - name: Upload Minified Files + uses: actions/upload-artifact@v3 + with: + name: minified-files-pico_w + path: ./pico_w/Gameberry/ + + json-to-python: + runs-on: ubuntu-latest + needs: minify + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download Minified Files + uses: actions/download-artifact@v3 + with: + name: minified-files-pico_w + path: ./pico_w/Gameberry/ + + - name: Setup Python + uses: actions/setup-python@v5.1.1 + + - name: Clone micropython_data_to_py + run: | + git clone https://github.com/peterhinch/micropython_data_to_py.git + + - name: Convert data to python + run: | + ./micropython_data_to_py/data_to_py.py ./pico_w/Gameberry/boot_config.json ./pico_w/Gameberry/boot_config.py + ./micropython_data_to_py/data_to_py.py ./pico_w/Gameberry/default/settings_default.json ./pico_w/Gameberry/default/settings_default.py + ./micropython_data_to_py/data_to_py.py ./pico_w/Gameberry/translations/pl.json ./pico_w/Gameberry/translations/pl.py + ./micropython_data_to_py/data_to_py.py ./pico_w/Gameberry/translations/en.json ./pico_w/Gameberry/translations/en.py + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: converted-files-pico_w + path: | + ./pico_w/Gameberry/ + build: + runs-on: ubuntu-latest + needs: json-to-python + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download Minified Files + uses: actions/download-artifact@v3 + with: + name: converted-files-pico_w + path: ./pico_w/Gameberry/ + + - name: Update apt-get + run: | + sudo apt-get update + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential python3 python3-pip libffi-dev pkg-config + pip3 install pyparsing + + - name: Clone MicroPython + run: | + git clone --depth 1 https://github.com/micropython/micropython.git + cd micropython + git submodule update --init --recursive + + - name: Build mpy-cross + run: | + cd micropython/mpy-cross + make clean + make + cd .. + cd .. + + - name: Add boot.py to _boot.py + run: | + cd micropython/ports/rp2 + ls ./modules + cat ./modules/_boot.py + cat ./modules/_boot_fat.py + cat /home/runner/work/GameBerry/GameBerry/pico_w/Gameberry/boot.py >> ./modules/_boot.py + cat /home/runner/work/GameBerry/GameBerry/pico_w/Gameberry/boot.py >> ./modules/_boot_fat.py + cat ./modules/_boot.py + cat ./modules/_boot_fat.py + cd .. + cd .. + cd .. + + - name: Build Raspberry Pi Pico W + run: | + cd micropython/ports/rp2 + make clean + make BOARD=RPI_PICO_W FROZEN_MANIFEST=/home/runner/work/GameBerry/GameBerry/pico_w/Gameberry/manifest.py + + - name: Upload Firmware Artifact + uses: actions/upload-artifact@v3 + with: + name: pico_w_uf2 + path: | + micropython/ports/rp2/build-RPI_PICO_W/firmware.uf2 + + - name: Get short commit SHA + id: get_short_sha + run: echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_ENV + + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.short_sha }} + release_name: ${{github.sha}} + draft: false + prerelease: true + + - uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: micropython/ports/rp2/build-RPI_PICO_W/firmware.uf2 + asset_name: RPI_PICO_W.uf2 + content_type: application/octet-stream + + - uses: eregon/publish-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + release_id: ${{ steps.create_release.outputs.id }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..051681f --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +settings.json +.vscode/ +.micropico +*.code-workspace +__pycache__ +extensions.json +octoprint-config.json +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b983dfb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-ast + - id: check-json + - id: pretty-format-json + - repo: https://github.com/gitleaks/gitleaks + rev: v8.18.4 + hooks: + - id: gitleaks \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..925a33b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Kitki30 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..08d48af --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ + +![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/Kitki30/Gameberry/total?label=Downloads) +# GameBerry + +Multi function software for micro controllers. + +### Supported micro controllers +- [Raspberry pi pico W / WH](https://github.com/Kitki30/GameBerry/blob/main/pico_w/README.MD) diff --git a/download_list_guide.md b/download_list_guide.md new file mode 100644 index 0000000..4da1230 --- /dev/null +++ b/download_list_guide.md @@ -0,0 +1,194 @@ +# Kitki30 Gameberry Download List File + +## What is download list +Download list is used in Gameberry installer, +it tells the installer what files to download, +what folders to create and many more! +Please read this guide if you want to contribute or make custom Gameberry version! + +## Basic elements of Download List + +### Info elements +Info elements tell the installer if file is a list and version of the list! +They need to be included or the list will not be recognized as a list, +and installer will abort its work! + +Kitki30-Gameberry-Download-List-File - Needs to be included (Line 1) +version 1.0 - Version of Download List - Needs to be included (Line 2) + +Begining of the list will look like this +``` +Kitki30-Gameberry-Download-List-File +version 1.0 +``` + +### START +START command needs to be included after info elements of download list +Your download list should look like this: +``` +Kitki30-Gameberry-Download-List-File +version 1.0 +START +``` + +## Commands +Commands are included after START of the Download List, +they tell installer what to do! + +Example: +``` +Kitki30-Gameberry-Download-List-File +version 1.0 +START +(you add commands here) +``` + +### download +Makes get request to URL and saves content to specified file! + +Elements of download command +First line of download: download +Second line of download: file path to were to save the file +Third line of download: URL to content that you want to download +> [!NOTE] +> File path should not be starting with / installer automaticly adds it at begining of the path! +> [!NOTE] +> Link to files from github should be link to raw file or the installer will download the code of github page! + +Example: +``` +download +file.py +https://www.kitki30.tk/file.py +``` + +### folder +Makes folder on devices flash memory + +Elements of folder command: +First line: folder +Second line: folder name +> [!NOTE] +> Folder path should not be starting with / installer automaticly adds it at begining of the path! + +Example: +``` +folder +my_folder +``` + +### message +Prints message with print() command +Message is also logged in log + +Elements of message command: +First line: message +Second line: your message + +Example: +``` +message +Hello +``` + +User using installer will see your message! + +### log-message +Same as message command but shows it only in log! + +Elements of log-message command: +First line: log-message +Second line: message you want to show in log + +Example: +``` +log-message +Hello +``` + +Message will be written to log + +### comment +Comments in list +Ignored by installer + +Comments can only be one line + +Example: +``` +comment +Hello +``` + +### wait +Wait some time before reading other lines of the list +Uses time.sleep() for waiting + +Elements of wait command: +First line: wait +Second line: time you want to wait + +Example: +``` +wait +0.5 +``` + +### write +Writes something to file! + +Elements of write command: +First line: write +Second line: file name +Third line: content +> [!NOTE] +> File path should not be starting with / installer automaticly adds it at begining of the path! +> [!NOTE] +> Content needs to fit in one line or installer will show unknown command errors! +> [!NOTE] +> This command will overwrite the file you are writing to, to append content to file use write-append command + +Example: +``` +write +file.py +# Content +``` + +### write-append +Appends / writes something to file! + +Elements of write-append command: +First line: write-append +Second line: file name +Third line: content +> [!NOTE] +> File path should not be starting with / installer automaticly adds it at begining of the path! +> [!NOTE] +> Content needs to fit in one line or installer will show unknown command errors! + +Example: +``` +write +file.py +# Content +``` + +### Variables +Comming soon... + +## Ending Download List +Simply add END at end of the list +This will tell the installer to stop reading the download list! + +Example: +``` +Kitki30-Gameberry-Download-List-File +version 1.0 +START +comment +Example command +END +``` + +You cannot add any commands after that! \ No newline at end of file diff --git a/guide.md b/guide.md new file mode 100644 index 0000000..1c2ee3c --- /dev/null +++ b/guide.md @@ -0,0 +1,4 @@ +# Gameberry installation guide + +Please select your microcontroller: +[Raspberry Pi Pico W](https://github.com/Kitki30/GameBerry/blob/main/pico_w/README.MD) \ No newline at end of file diff --git a/pico_w/Gameberry/boot_config.json b/pico_w/Gameberry/boot_config.json new file mode 100644 index 0000000..b6d97f6 --- /dev/null +++ b/pico_w/Gameberry/boot_config.json @@ -0,0 +1,10 @@ +{ + "main": { + "name": "Gameberry", + "file": "/gameberry.py" + }, + "setup": { + "name": "Gameberry WebSetup", + "file": "/webSetup/webSetup.py" + } +} \ No newline at end of file diff --git a/pico_w/Gameberry/default/settings_default.json b/pico_w/Gameberry/default/settings_default.json new file mode 100644 index 0000000..bc3acc9 --- /dev/null +++ b/pico_w/Gameberry/default/settings_default.json @@ -0,0 +1,17 @@ +{ + "buzzer_volume": 1000, + "lcd_brightness": 255, + "language": "en", + "timezone": { + "timezone": 2, + "timezone_on_minus": false + }, + "Wi-Fi": { + "wifi_ssid": "", + "wifi_password": "" + }, + "Battery": { + "capacity": 4000, + "is_used": true + } +} \ No newline at end of file diff --git a/pico_w/Gameberry/device_config.json b/pico_w/Gameberry/device_config.json new file mode 100644 index 0000000..6271d25 --- /dev/null +++ b/pico_w/Gameberry/device_config.json @@ -0,0 +1,4 @@ +{ + "INA219": true, + "SD_READER": true +} \ No newline at end of file diff --git a/pico_w/Gameberry/game/game.py b/pico_w/Gameberry/game/game.py new file mode 100644 index 0000000..d425a3f --- /dev/null +++ b/pico_w/Gameberry/game/game.py @@ -0,0 +1,74 @@ +import time +from machine import Pin +import modules.saveDataManager as saveDataManager +import machine +import modules.gameSystemMenu as sysMenu + +button1 = Pin(3, Pin.IN, Pin.PULL_UP) # First button (GPIO3) +button2 = Pin(2, Pin.IN, Pin.PULL_UP) # Second button (GPIO2) +home = Pin(15, Pin.IN, Pin.PULL_UP) # Home +fixerBtn1 = 1 +clicks = 0 +saveData = None +saveclicks = 0 + +def run(wlan, lcd): + print("BerryClicker is running!") + global fixerBtn1 + global saveData + global saveclicks + global clicks + loadingData(lcd) + clicks = saveData["clicks"] # Even if shows error in IDE please leave it like that, its read on line 18 + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("BerryClicker") + lcd.setCursor(0,1) + lcd.printout("Kitki30") + time.sleep(0.5) + main(lcd) + while True: + if button1.value() == 0 and fixerBtn1 == 1: + clicks = clicks + 1 + saveclicks = saveclicks + 1 + if saveclicks == 100: + saveclicks = 0 + save(lcd) + fixerBtn1 = 0 + main(lcd) + elif button1.value() == 1: + fixerBtn1 = 1 + if home.value() == 0: + save(lcd) + sysMenu.show(lcd) + loadingData(lcd) + main(lcd) + time.sleep(0.025) + +def main(lcd): + global clicks + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Clicks: ") + lcd.setCursor(0,1) + lcd.printout(str(clicks)) + +def loadingData(lcd): + global saveData + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading data!") + lcd.setCursor(0,1) + lcd.printout("Please wait...") + time.sleep(0.2) + saveData = saveDataManager.load() + +def save(lcd): + global saveData + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Saving data!") + lcd.setCursor(0,1) + lcd.printout("Please wait...") + saveData['clicks'] = clicks + saveDataManager.save(saveData) \ No newline at end of file diff --git a/pico_w/Gameberry/game/game_info.json b/pico_w/Gameberry/game/game_info.json new file mode 100644 index 0000000..350702c --- /dev/null +++ b/pico_w/Gameberry/game/game_info.json @@ -0,0 +1,10 @@ +{ + "name": "BerryClicker", + "author": "Kitki30", + "license": "MIT", + "id": "O00000", + "saveDataManager": { + "default": "save_default.json", + "format": "json" + } +} \ No newline at end of file diff --git a/pico_w/Gameberry/game/save_default.json b/pico_w/Gameberry/game/save_default.json new file mode 100644 index 0000000..d314ae6 --- /dev/null +++ b/pico_w/Gameberry/game/save_default.json @@ -0,0 +1,3 @@ +{ + "clicks": 0 +} \ No newline at end of file diff --git a/pico_w/Gameberry/gameberry.py b/pico_w/Gameberry/gameberry.py new file mode 100644 index 0000000..135e081 --- /dev/null +++ b/pico_w/Gameberry/gameberry.py @@ -0,0 +1,861 @@ +import modules.RGB1602 as RGB1602 +import uos +import modules.json as json +import utime as time, utime +from machine import Pin, PWM +import machine +import network +import modules.files as files +import modules.ntp as ntp +import gc +import modules.customExceptions as exceptions +import modules.translations as translation +import os + +events_working = False +runEvents = True + +version = 0.8 + +gc.collect() + + +# Initialize buttons +button1 = Pin(3, Pin.IN, Pin.PULL_UP) # First button (GPIO3) +button2 = Pin(2, Pin.IN, Pin.PULL_UP) # Second button (GPIO2) +home = Pin(15, Pin.IN, Pin.PULL_UP) # Home button (GPIO15) +button1state = 1 +button2state = 1 +homestate = 1 + +safeboot = False + +if home.value() == 0: + safeboot = True + while safeboot == True: + print("Machine is in safeboot") + print("Press button 1 to continue!") + if button1.value() == 0: + safeboot = False + time.sleep(5) + +lcd=RGB1602.RGB1602(16,2) +lcd.clear() +if files.exist("/settings.json"): + print(translation.get("debugger", "settings_exist")) # Settings exist! +else: + if files.exist("/default/settings_default.json"): + try: + files.copy("/default/settings_default.json", "/settings.json") + except: + exceptions.ShowErrorScreen_with_code(lcd, "file_copy_error") + raise exceptions.FileCopyError("Cannot copy /default/settings_default.json to /settings.json! Cannot boot!") + else: + exceptions.ShowErrorScreen_with_code(lcd, "defaults_error") + raise exceptions.DefaultsNotFound("Default file /default/settings_default.json, not found! Cannot boot!") +data = json.read("/settings.json") + +import modules.time as timezones + +translation.load(data["language"]) + +# Gameberry logo +timeFormatted = utime.localtime(timezones.get_timezoned()) +print("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=") +print("GameBerry v"+str(version)+" "+ translation.get("debugger", "gameberry_on") +" "+ uos.uname().machine) # Gameberry v{version} on {machine name} +print(translation.get("debugger", "machine_freq")+": "+str(machine.freq() / 1000000)+" Mhz") # Machine frequency: {freq}Mhz +print(str(timeFormatted[2])+"."+str(timeFormatted[1])+"."+str(timeFormatted[0])+" "+str(timeFormatted[3])+":"+str(timeFormatted[4])+":"+str(timeFormatted[5])) +print("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=") + +# RTC Clock +rtc = machine.RTC() + + + + + + + +if files.exist("/savedata"): + print(translation.get("debugger", "savedata_exist")) # Savedata exist! +else: + files.create_folder("/savedata") + + + +# Start connecting to Wi-Fi +wifiExists = False + +wlan = network.WLAN(network.STA_IF) +wlan.active(True) +wlan.connect(data.get("Wi-Fi").get("wifi_ssid"), data.get("Wi-Fi").get("wifi_password")) + +import modules.basicThread +modules.basicThread.start() + +# Led blink +print(translation.get("debugger", "waiting_one_second")) # Waiting one second +led = Pin("LED", Pin.OUT) +blinks = 0 +while blinks is not 10: + blinks = blinks + 1 + time.sleep(0.025) + led.on() + time.sleep(0.025) + led.off() +led.on() + + + + +# Boot screen +_temp_lcd_brightness = data.get('lcd_brightness') +lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) +lcd.printout("GameBerry") +lcd.setCursor(0,1) +lcd.printout("Kitki30") +time.sleep(0.5) +lcd.clear() + +""" + STAT_IDLE -- 0 + STAT_CONNECTING -- 1 + STAT_WRONG_PASSWORD -- -3 + STAT_NO_AP_FOUND -- -2 + STAT_CONNECT_FAIL -- -1 + STAT_GOT_IP -- 3 +""" + +# Buzzer (GPIO16) +buzzer = PWM(Pin(16, Pin.OUT)) +buzzer.duty_u16(0) + +# Connect to wifi +lcd.setCursor(0,0) +lcd.printout(translation.get("wifi", "connecting_to")) # Connecting to +lcd.setCursor(0,1) +if len(data.get("Wi-Fi").get("wifi_ssid")) > 16: + lcd.printout("Wi-Fi") +else: + lcd.printout(data.get("Wi-Fi").get("wifi_ssid")) +wifiChecks = 0 +connectBlock = False +while wlan.isconnected() == False and wifiChecks is not 200 and connectBlock == False: + if wlan.status() == -1: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout(translation.get("global", "error")) # Error + lcd.setCursor(0,1) + lcd.printout(translation.get("wifi", "connection_fail")) # Connection Fail + connectBlock = True + time.sleep(1) + elif wlan.status() == -2: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout(translation.get("global", "error")) # Error + lcd.setCursor(0,1) + lcd.printout(translation.get("wifi", "ap_not_found")) # AP not found + connectBlock = True + time.sleep(1) + elif wlan.status() == -3: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout(translation.get("global", "error")) # Error + lcd.setCursor(0,1) + lcd.printout(translation.get("wifi", "wrong_password")) # Wrong password + connectBlock = True + time.sleep(1) + wifiChecks = wifiChecks + 1 + led.off() + time.sleep(0.05) + led.on() + time.sleep(0.05) +led.on() + + + + +# Menu + +# Menu variables +currentMenu = 0 + +# Main menu +def main(): + global currentMenu + currentMenu = 0 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + if files.exist("/game/game_info.json"): + gameInfo = json.read("/game/game_info.json") + lcd.printout(gameInfo["name"]) + else: + lcd.printout(translation.get("global", "game")) # Game + lcd.setCursor(0,1) + lcd.printout(translation.get("menu", "play_next")) # 1. Play 2. Next + print("Current menu: "+str(currentMenu)) + +# Settings menu +def settings(): + global currentMenu + currentMenu = 1 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout(translation.get("global", "settings")) # Settings + lcd.setCursor(0,1) + lcd.printout(translation.get("menu", "ok_next")) # 1. OK 2. Next + print("Current menu: "+str(currentMenu)) + +# Exit +def exit(): + global currentMenu + currentMenu = 2 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout(translation.get("global", "exit")) # Exit + lcd.setCursor(0,1) + lcd.printout(translation.get("menu", "exit_next")) # 1. Exit 2. Next + print("Current menu: "+str(currentMenu)) + +def play(): + try: + ram = gc.mem_free() / 1024 + gc.collect() + print("Cleaned garbage!!!") + print(str((gc.mem_free() / 1024)) + "KB Ram free" + " was "+str(ram)+"KB") + import game.game as game + print("Game imported, launching...") + lcd.clear() + game.run(wlan, lcd) + machine.reset() + except ImportError as e: + print(f"Failed to import the game: {e}") + print("Rebooting") + lcd.clear() + temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Game not found") + lcd.setCursor(0,1) + lcd.printout("Rebooting...") + time.sleep(1) + reset() + +def reset(): + print("Soft reset process started...") + print("Disabling power led") + led.off() + lcd.setRGB(0,0,0) + lcd.clear() + print("Rebooting...") + machine.soft_reset() + +def settings1(): + global currentMenu + currentMenu = 3 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Machine") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_display(): + global currentMenu + currentMenu = 18 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Display") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_display_brightness_selector(): + global currentMenu + currentMenu = 21 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout(str(data.get('lcd_brightness'))) + lcd.setCursor(0,1) + lcd.printout("1. + 2. -") + print("Current menu: "+str(currentMenu)) + +def settings_display_brightness(): + global currentMenu + currentMenu = 19 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Brightness") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_display_back(): + global currentMenu + currentMenu = 20 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_buzzer(): + global currentMenu + currentMenu = 22 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Buzzer") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_buzzer_volume(): + global currentMenu + currentMenu = 23 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Volume") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings_buzzer_volume_selection(): + global currentMenu + currentMenu = 25 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout(str(data.get('buzzer_volume'))) + lcd.setCursor(0,1) + lcd.printout("1. + 2. -") + print("Current menu: "+str(currentMenu)) + +def settings_buzzer_back(): + global currentMenu + currentMenu = 24 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings2(): + global currentMenu + currentMenu = 14 + lcd.clear() + temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings3(): + global currentMenu + currentMenu = 15 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Bootloader") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings4(): + global currentMenu + currentMenu = 16 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def settings5(): + global currentMenu + currentMenu = 17 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Enter Bootloader") + lcd.setCursor(0,1) + lcd.printout("1. Yes 2. No") + print("Current menu: "+str(currentMenu)) + +def exit1(): + gc.collect() + print("Prepairing to shutdown...") + global currentMenu + currentMenu = 4 + wlan.disconnect() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + + time.sleep(2) + lcd.clear() + lcd.setRGB(0,0,0) + led.off() + wlan.disconnect() + wlan.active(False) + while True: + time.sleep(10) + if button1.value() == 0: + machine.soft_reset() + + +def apps1(): + global currentMenu + currentMenu = 7 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Apps") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def apps(): + global currentMenu + currentMenu = 5 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Wi-Fi") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def appsExit(): + global currentMenu + currentMenu = 6 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def time1(): + global currentMenu + currentMenu = 10 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("What time is it?") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def whatTimeIsIt1(): + global currentMenu + currentMenu = 11 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + timeFormatted = utime.localtime(timezones.get_timezoned()) + + lcd.printout(str(timeFormatted[3])+":"+str(timeFormatted[4])+":"+str(timeFormatted[5])) + lcd.setCursor(0,1) + lcd.printout(" 2. Next") + print("Current menu: "+str(currentMenu)) + +def whatTimeIsIt2(): + global currentMenu + currentMenu = 12 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + timeFormatted = utime.localtime(timezones.get_timezoned()) + lcd.printout(str(timeFormatted[2])+"."+str(timeFormatted[1])+"."+str(timeFormatted[0])) + lcd.setCursor(0,1) + lcd.printout(" 2. Next") + print("Current menu: "+str(currentMenu)) + + +def whatTimeIsIt3(): + global currentMenu + currentMenu = 13 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Back") + lcd.setCursor(0,1) + lcd.printout("1. Back 2. Next") + print("Current menu: "+str(currentMenu)) + +def wifi(): + global currentMenu + currentMenu = 8 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + if len(data.get("Wi-Fi").get("wifi_ssid")) > 16: + lcd.printout("Wi-Fi") + else: + lcd.printout(data.get("Wi-Fi").get("wifi_ssid")) + lcd.setCursor(0,1) + lcd.printout("1. Back 2. Next") + print("Current menu: "+str(currentMenu)) + +def wifiConnect(): + global currentMenu + currentMenu = 9 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + if wlan.isconnected() == False: + lcd.printout("Connect") + else: + lcd.printout("Disconnect") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def connect(): + print("Connecting to wlan...") + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("Connecting to") + lcd.setCursor(0,1) + if len(data.get("Wi-Fi").get("wifi_ssid")) > 16: + lcd.printout("Wi-Fi") + else: + lcd.printout(data.get("Wi-Fi").get("wifi_ssid")) + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + wlan.connect(data.get("Wi-Fi").get("wifi_ssid"), data.get("Wi-Fi").get("wifi_password")) + lcd.setCursor(0,0) + lcd.printout("Connecting to") + lcd.setCursor(0,1) + if len(data.get("Wi-Fi").get("wifi_ssid")) > 16: + lcd.printout("Wi-Fi") + else: + lcd.printout(data.get("Wi-Fi").get("wifi_ssid")) + wifiChecks = 0 + connectBlock = False + while wlan.isconnected() == False and wifiChecks is not 200 and connectBlock == False: + if wlan.status() == -1: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Error") + lcd.setCursor(0,1) + lcd.printout("Connection Fail") + connectBlock = True + time.sleep(1) + elif wlan.status() == -2: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Error") + lcd.setCursor(0,1) + lcd.printout("AP not found") + connectBlock = True + time.sleep(1) + elif wlan.status() == -3: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Error") + lcd.setCursor(0,1) + lcd.printout("Wrong password") + connectBlock = True + time.sleep(1) + wifiChecks = wifiChecks + 1 + led.off() + time.sleep(0.05) + led.on() + time.sleep(0.05) + led.on() + if wlan.isconnected() == False: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Connection failed!") + print("Connection failed") + time.sleep(1) + + # Sync clock + if wlan.isconnected() == True and timeFormatted[0] < 2024: + print("Sync rtc clock..") + lcd.clear() + lcd.printout("Setting clock...") + ntp.sync(wlan) + +def OctoPrint1(): + global currentMenu + currentMenu = 30 + lcd.clear() + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.setCursor(0,0) + lcd.printout("OctoPrint") + lcd.setCursor(0,1) + lcd.printout("1. OK 2. Next") + print("Current menu: "+str(currentMenu)) + +def OctoPrint(): + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading...") + lcd.setCursor(0,1) + lcd.printout("0/3") + file1 = False + file2 = False + if files.exist("/plugins/octoprint.py"): + file1 = True + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading...") + lcd.setCursor(0,1) + lcd.printout("1/3") + if files.exist("/plugins/octolib.py"): + file2 = True + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading...") + lcd.setCursor(0,1) + lcd.printout("2/3") + if file1 == True and file2 == True: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading...") + lcd.setCursor(0,1) + lcd.printout("3/3") + import plugins.octoprint as ocp + ocp.start(lcd) + else: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Please install") + lcd.setCursor(0,1) + lcd.printout("OctoPrint Plugin") + time.sleep(1) + main() + +# Sync clock +if wlan.isconnected() == True: + print(translation.get("rtc", "debugger_rtc")) # Sync rtc clock... + lcd.clear() + lcd.printout(translation.get("rtc", "setting_clock")) # Setting clock... + ntp.sync(wlan) + if files.exist("/startOptions.gameberry"): + f = open('/startOptions.gameberry') + if f.read() == "octo-plugin": + f.close() + os.remove('/startOptions.gameberry') + OctoPrint() + + +print("Going to the menu for first time...") +main() + + +while True: + + if button1.value() == 0 and button1state == 1: + button1state = 0 + buzzer.duty_u16(data.get('buzzer_volume')) + buzzer.freq(659) + time.sleep(0.1) + buzzer.duty_u16(0) + if currentMenu == 0: + play() + elif currentMenu == 1: + settings1() + elif currentMenu == 7: + apps() + elif currentMenu == 2: + exit1() + elif currentMenu == 6: + apps1() + elif currentMenu == 5: + wifi() + elif currentMenu == 9: + if wlan.isconnected() == True: + wlan.disconnect() + else: + connect() + wifi() + elif currentMenu == 8: + apps() + elif currentMenu == 13: + time1() + elif currentMenu == 10: + whatTimeIsIt1() + elif currentMenu == 14: + settings() + elif currentMenu == 3: + settings3() + elif currentMenu == 16: + settings1() + elif currentMenu == 15: + settings5() + elif currentMenu == 17: + print("Entering bootloader(BOOTSEL)") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Entering") + lcd.setCursor(0,1) + lcd.printout("bootloader...") + time.sleep(1) + lcd.clear() + lcd.setRGB(0,0,0) + machine.bootloader() + elif currentMenu == 18: + settings_display_brightness() + elif currentMenu == 20: + settings_display() + elif currentMenu == 19: + settings_display_brightness_selector() + elif currentMenu == 21: + if data['lcd_brightness'] is not 255: + data['lcd_brightness'] = data['lcd_brightness'] + 5 + json.write("/settings.json", data) + settings_display_brightness_selector() + elif currentMenu == 22: + settings_buzzer_volume() + elif currentMenu == 23: + settings_buzzer_volume_selection() + elif currentMenu == 24: + settings_buzzer() + elif currentMenu == 25: + if data['buzzer_volume'] is not 2000: + data['buzzer_volume'] = data['buzzer_volume'] + 100 + json.write("/settings.json", data) + settings_buzzer_volume_selection() + elif currentMenu == 30: + OctoPrint() + elif button1.value() == 1 and button1state == 0: + print("Button state updated") + button1state = 1 + + if button2.value() == 0 and button2state == 1: + button2state = 0 + buzzer.duty_u16(data.get('buzzer_volume')) + buzzer.freq(659) + time.sleep(0.05) + buzzer.duty_u16(0) + if currentMenu == 0: + apps1() + elif currentMenu == 7: + settings() + elif currentMenu == 1: + exit() + elif currentMenu == 2: + main() + elif currentMenu == 5: + time1() + elif currentMenu == 6: + apps() + elif currentMenu == 8: + wifiConnect() + elif currentMenu == 9: + wifi() + elif currentMenu == 10: + OctoPrint1() + elif currentMenu == 30: + appsExit() + elif currentMenu == 11: + whatTimeIsIt2() + elif currentMenu == 12: + whatTimeIsIt3() + elif currentMenu == 13: + whatTimeIsIt1() + elif currentMenu == 14: + settings1() + elif currentMenu == 3: + settings_display() + elif currentMenu == 17: + settings3() + elif currentMenu == 16: + settings3() + elif currentMenu == 15: + settings4() + elif currentMenu == 18: + settings_buzzer() + elif currentMenu == 19: + settings_display_back() + elif currentMenu == 20: + settings_display_brightness() + elif currentMenu == 21: + if data['lcd_brightness'] is not 0: + data['lcd_brightness'] = data['lcd_brightness'] - 5 + json.write("/settings.json", data) + settings_display_brightness_selector() + elif currentMenu == 22: + settings2() + elif currentMenu == 23: + settings_buzzer_back() + elif currentMenu == 24: + settings_buzzer_volume() + elif currentMenu == 25: + if data['buzzer_volume'] is not 0: + data['buzzer_volume'] = data['buzzer_volume'] - 100 + json.write("/settings.json", data) + settings_buzzer_volume_selection() + elif button2.value() == 1 and button2state == 0: + print("Button state updated") + button2state = 1 + + if home.value() == 0 and homestate == 1: + gc.collect() + homestate = 0 + buzzer.duty_u16(data.get('buzzer_volume')) + buzzer.freq(659) + time.sleep(0.05) + buzzer.duty_u16(0) + if currentMenu == 21: + settings_display_brightness() + elif currentMenu == 25: + settings_buzzer_volume() + else: + main() + elif home.value() == 1 and homestate == 0: + print("Button state updated") + homestate = 1 + + if currentMenu == 11: + whatTimeIsIt1() + elif currentMenu == 12: + whatTimeIsIt2() + + + time.sleep(0.025) \ No newline at end of file diff --git a/pico_w/Gameberry/main.py b/pico_w/Gameberry/main.py new file mode 100644 index 0000000..290f1e2 --- /dev/null +++ b/pico_w/Gameberry/main.py @@ -0,0 +1,150 @@ +# POST + +# Blink code: +# Broken lcd - 3 blinks +# Broken lcd - 4 blinks + +version = 1.0 + +print("POST:") +import machine +import modules.customExceptions +import modules.blinker as blinker +import modules.json as json +import modules.files as files +import time + +led = machine.Pin("LED", machine.Pin.OUT) +led.on() + +postBypass = machine.Pin(22, machine.Pin.IN, machine.Pin.PULL_DOWN) + +# Post skip +if postBypass.value() == 1: + print("POST Skipped with GPIO22 PIN!") + +# Flash memory +if postBypass.value() == 0: + try: + import random + letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + digits = '0123456789' + chars = letters + digits + random1 = ''.join(random.choice(chars) for _ in range(64)) + with open("/power_on_self_test_file", 'wb') as file: + file.write(random1.encode('utf-8')) + with open("/power_on_self_test_file", 'rb') as file: + readed = file.read().decode('utf-8') + if random1 == readed: + print("Flash memory - Working") + else: + raise modules.customExceptions.FileReadWriteError("Test file content was different when writing({}) and when reading({})".format(random1,readed)) + except Exception as exception: + print("Flash memory - Broken") + blinker.blink(4, 0.25) + raise modules.customExceptions.FileReadWriteError("Error happened when reading/writing to flash memory!\nError:\n"+str(exception)) + +# LCD +if postBypass.value() == 0: + try: + import modules.RGB1602 as l + lcd = l.RGB1602(16,2) + i = 0 + i2 = 0 + lcd.setCursor(0,0) + lcd.setRGB(0,0,0) + while i is not 2: + while i2 is not 16: + lcd.write(7) + i2 = i2 + 1 + lcd.setCursor(0,1) + i = i + 1 + lcd.clear() + print("LCD - Working") + lcd.clear() + lcd.setColorWhite() + lcd.setCursor(0,0) + lcd.printout("Gameberry Boot") + lcd.setCursor(0,1) + lcd.printout("Manager v"+str(version)) + except OSError as osError: + print("LCD - Broken\n") + blinker.blink(3, 0.25) + raise modules.customExceptions.LcdDisplayError("LCD Display is not connected or has broken please check the display and connection to the board!\nError:\n"+str(osError)) + + +buzzer = machine.PWM(machine.Pin(16, machine.Pin.OUT)) +buzzer.duty_u16(2000) +buzzer.freq(659) +time.sleep(0.1) +buzzer.duty_u16(0) + +boot_config = json.read("/boot_config.json") + +print("\nAll things working ready to boot!") + +# Boot +if files.exist(boot_config["main"]["file"]): + print("Booting main...") + exec(open(boot_config["main"]["file"]).read()) +else: + buzzer.duty_u16(2000) + buzzer.freq(700) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + if files.exist(boot_config["recovery"]["file"]): + print("Booting recovery...") + boot_config = json.read_from_string("/device_config.json") + exec(open(boot_config["recovery"]["file"]).read()) + else: + buzzer.duty_u16(2000) + buzzer.freq(600) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + try: + print("Mounting SD Card...") + import modules.sd + modules.sd.start() + modules.sd.mount("/recovery") + print("Booting SD recovery") + exec(open("/recovery/recovery/recovery.py").read()) + except: + buzzer.duty_u16(2000) + buzzer.freq(500) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + time.sleep(0.1) + buzzer.duty_u16(0) + time.sleep(0.1) + buzzer.duty_u16(2000) + buzzer.freq(200) + time.sleep(0.50) + buzzer.duty_u16(0) + import modules.RGB1602 as l + lcd = l.RGB1602(16,2) + modules.customExceptions.ShowErrorScreen_with_code(lcd, "no_boot_options") + print("Error: No more boot options, please install gameberry or insert recovery SD") + \ No newline at end of file diff --git a/pico_w/Gameberry/modules/RGB1602.py b/pico_w/Gameberry/modules/RGB1602.py new file mode 100644 index 0000000..4504997 --- /dev/null +++ b/pico_w/Gameberry/modules/RGB1602.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +import time +from machine import Pin,I2C +import modules.characterSets as charSets + +RGB1602_SDA = Pin(4) +RGB1602_SCL = Pin(5) + +RGB1602_I2C = I2C(0,sda = RGB1602_SDA,scl = RGB1602_SCL ,freq = 400000) + +#Device I2C Arress +LCD_ADDRESS = (0x7c>>1) +RGB_ADDRESS = (0xc0>>1) + +#color define + +REG_RED = 0x04 +REG_GREEN = 0x03 +REG_BLUE = 0x02 +REG_MODE1 = 0x00 +REG_MODE2 = 0x01 +REG_OUTPUT = 0x08 +LCD_CLEARDISPLAY = 0x01 +LCD_RETURNHOME = 0x02 +LCD_ENTRYMODESET = 0x04 +LCD_DISPLAYCONTROL = 0x08 +LCD_CURSORSHIFT = 0x10 +LCD_FUNCTIONSET = 0x20 +LCD_SETCGRAMADDR = 0x40 +LCD_SETDDRAMADDR = 0x80 + +#flags for display entry mode +LCD_ENTRYRIGHT = 0x00 +LCD_ENTRYLEFT = 0x02 +LCD_ENTRYSHIFTINCREMENT = 0x01 +LCD_ENTRYSHIFTDECREMENT = 0x00 + +#flags for display on/off control +LCD_DISPLAYON = 0x04 +LCD_DISPLAYOFF = 0x00 +LCD_CURSORON = 0x02 +LCD_CURSOROFF = 0x00 +LCD_BLINKON = 0x01 +LCD_BLINKOFF = 0x00 + +#flags for display/cursor shift +LCD_DISPLAYMOVE = 0x08 +LCD_CURSORMOVE = 0x00 +LCD_MOVERIGHT = 0x04 +LCD_MOVELEFT = 0x00 + +#flags for function set +LCD_8BITMODE = 0x10 +LCD_4BITMODE = 0x00 +LCD_2LINE = 0x08 +LCD_1LINE = 0x00 +LCD_5x8DOTS = 0x00 + + +class RGB1602: + def __init__(self, col, row): + self._row = row + self._col = col + + self._showfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + self.begin(self._row,self._col) + + + def command(self,cmd): + RGB1602_I2C.writeto_mem(LCD_ADDRESS, 0x80, chr(cmd)) + + def write(self,data): + RGB1602_I2C.writeto_mem(LCD_ADDRESS, 0x40, chr(data)) + + def setReg(self,reg,data): + RGB1602_I2C.writeto_mem(RGB_ADDRESS, reg, chr(data)) + + + def setRGB(self,r,g,b): + self.setReg(REG_RED,r) + self.setReg(REG_GREEN,g) + self.setReg(REG_BLUE,b) + + def setCursor(self,col,row): + if(row == 0): + col|=0x80 + else: + col|=0xc0; + RGB1602_I2C.writeto(LCD_ADDRESS, bytearray([0x80,col])) + + def clear(self): + self.command(LCD_CLEARDISPLAY) + time.sleep(0.002) + + def printout(self,arg): + if(isinstance(arg,int)): + arg=str(arg) + + for x in bytearray(arg,'utf-8'): + self.write(x) + + + def display(self): + self._showcontrol |= LCD_DISPLAYON + self.command(LCD_DISPLAYCONTROL | self._showcontrol) + + + def begin(self,cols,lines): + if (lines > 1): + self._showfunction |= LCD_2LINE + + self._numlines = lines + self._currline = 0 + + + + time.sleep(0.05) + + + # Send function set command sequence + self.command(LCD_FUNCTIONSET | self._showfunction) + #delayMicroseconds(4500); # wait more than 4.1ms + time.sleep(0.005) + # second try + self.command(LCD_FUNCTIONSET | self._showfunction); + #delayMicroseconds(150); + time.sleep(0.005) + # third go + self.command(LCD_FUNCTIONSET | self._showfunction) + # finally, set # lines, font size, etc. + self.command(LCD_FUNCTIONSET | self._showfunction) + # turn the display on with no cursor or blinking default + self._showcontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF + self.display() + # clear it off + self.clear() + # Initialize to default text direction (for romance languages) + self._showmode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT + # set the entry mode + self.command(LCD_ENTRYMODESET | self._showmode); + # backlight init + self.setReg(REG_MODE1, 0) + # set LEDs controllable by both PWM and GRPPWM registers + self.setReg(REG_OUTPUT, 0xFF) + # set MODE2 values + # 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode) + self.setReg(REG_MODE2, 0x20) + charSets.default(self) + self.setColorWhite() + + def create_custom_char(self, location, charmap): + location &= 0x7 + self.command(LCD_SETCGRAMADDR | (location << 3)) + for i in range(8): + self.write(charmap[i]) + + def setColorWhite(self): + self.setRGB(255, 255, 255) diff --git a/pico_w/Gameberry/modules/basicThread.py b/pico_w/Gameberry/modules/basicThread.py new file mode 100644 index 0000000..397da02 --- /dev/null +++ b/pico_w/Gameberry/modules/basicThread.py @@ -0,0 +1,58 @@ +import _thread +import gc +import time +import modules.json as json +import ujson +import modules.sdcard as sdcard +import machine +import modules.customExceptions as exceptions +import modules.RGB1602 as RGB1602 +import os + +thread_active = False +threadTime = 0 +thread_monitor_sd_card = False +thread_reset_time = 5 +sd_not_used = True + +def thread_activity(): + print("Starting basicThread") + global thread_active + global thread_monitor_sd_card + global threadTime + global sd_not_used + global thread_reset_time + while thread_active == True: + threadTime = threadTime + 1 + thread_temp_file = json.read("/thread_temp_file.json") + thread_active = thread_temp_file["active"] + thread_monitor_sd_card = thread_temp_file["sd_monitor"] + sd_not_used = thread_temp_file["sd_not_used"] + if thread_monitor_sd_card == True: + if threadTime == 5 and sd_not_used == True: + print("Checking SD Card...") + cs = machine.Pin(13, machine.Pin.OUT) + spi = machine.SPI(1, + baudrate=1000000, + polarity=0, + phase=0, + bits=8, + firstbit=machine.SPI.MSB, + sck=machine.Pin(10), + mosi=machine.Pin(11), + miso=machine.Pin(12)) + sd = sdcard.SDCard(spi, cs) + if sd.is_present() == False: + lcd = RGB1602.RGB1602(16,2) + exceptions.ShowErrorScreen_with_code(lcd, "SD_CARD_ERROR") + if threadTime == thread_reset_time: + threadTime = 0 + time.sleep(1) + print("Stopping basicThread") + os.remove("/thread_temp_file.json") + print("Stopped") + +def start(): + thread_active = True + json.write("/thread_temp_file.json", ujson.dumps({"active": thread_active, "sd_monitor": thread_monitor_sd_card, "sd_not_used": sd_not_used})) + _thread.start_new_thread(thread_activity, ()) diff --git a/pico_w/Gameberry/modules/battery.py b/pico_w/Gameberry/modules/battery.py new file mode 100644 index 0000000..1dbef94 --- /dev/null +++ b/pico_w/Gameberry/modules/battery.py @@ -0,0 +1,93 @@ +import modules.ina219 as ina219 +import modules.RGB1602 as RGB1602 +from machine import Pin,I2C +import modules.json as json +import time +import modules.math as math +import machine +import network + +def calculate_battery_level(V_current, V_min, V_max): + # Ensure the current voltage is within the expected range + if V_current < V_min: + V_current = V_min + elif V_current > V_max: + V_current = V_max + + # Calculate the battery level as a percentage + battery_level_percent = ((V_current - V_min) / (V_max - V_min)) * 100 + return int(round(battery_level_percent)) # Round to the nearest whole number + +def calculate_discharge_time(capacity_mAh, discharge_current_mA): + discharge_current_mA = abs(discharge_current_mA) + if discharge_current_mA <= 0: + raise ValueError("Discharge current must be greater than zero.") + + discharge_time_hours = capacity_mAh / discharge_current_mA + return discharge_time_hours + +def calibrate(): + battery = json.read("/settings.json") + capacity = battery["Battery"]["capacity"] + charge_max_V = 0.0 + charge_min_V = 0.0 + button1 = Pin(3, Pin.IN, Pin.PULL_UP) # First button (GPIO3) + button2 = Pin(2, Pin.IN, Pin.PULL_UP) # Second button (GPIO2) + home = Pin(15, Pin.IN, Pin.PULL_UP) # Home button (GPIO15) + lcd = RGB1602.RGB1602(16,2) + lcd.setCursor(0,0) + i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000) + SHUNT_OHMS = 0.1 + ina = ina219.INA219(SHUNT_OHMS, i2c) + lcd.printout("Charge battery t") + lcd.setCursor(0,1) + lcd.printout("o max click home") + while home.value() == 1: + time.sleep(.05) + if math.is_positive(ina.current()) == True: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Error: Charger") + lcd.setCursor(0,0) + lcd.printout("is connected!") + time.sleep(5) + machine.soft_reset() + charge_max_V = round(ina.bus_voltage(), 2) + json.write("/battery_calibration.json", { "max_V": charge_max_V, "min_V": charge_min_V, "calibration_in_progress": True }) + lcd.clear() + lcd.setRGB(255,255,255) + lcd.setCursor(0,0) + lcd.printout("Discharging") + lcd.setCursor(0,1) + lcd.printout("Don't charge") + i = 0 + fileWrite = 1 + print("Calibration") + print("Capacity read: "+str(capacity)+"mah") + print("Max voltage: "+str(charge_max_V) +"V") + print("Activating Wi-Fi module for faster discharge") + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + while True: + i = i + 1 + if i == 1000000 / 2: + wlan.scan() + if i == 1000000: + charge_min_V = round(ina.bus_voltage(), 2) + if fileWrite == 1: # Write to two files to avoid corruption of config on battery power loss + json.write("/battery_calibration.json", { "max_V": charge_max_V, "min_V": charge_min_V, "calibration_in_progress": True }) + fileWrite = 2 + else: + json.write("/battery_calibration2.json", { "max_V": charge_max_V, "min_V": charge_min_V, "calibration_in_progress": True }) + fileWrite = 1 + lcd.clear() + lcd.setRGB(255,255,255) + lcd.setCursor(0,0) + lcd.printout("Calibration...") + lcd.setCursor(0,1) + lcd.printout("ETA: "+ str(round(calculate_discharge_time(capacity, ina.current()), 1))+"h") + print("ETA: "+ str(round(calculate_discharge_time(capacity, ina.current()), 1))+"h") + print("Battery voltage: "+str(round(ina.bus_voltage(), 2)) + "V") + print("Current: "+str(ina.current())+"mA") + print("Power: "+str(ina.power())+"mW") + i = 0 \ No newline at end of file diff --git a/pico_w/Gameberry/modules/blinker.py b/pico_w/Gameberry/modules/blinker.py new file mode 100644 index 0000000..7ed9aa2 --- /dev/null +++ b/pico_w/Gameberry/modules/blinker.py @@ -0,0 +1,11 @@ +import machine +import time +def blink(blinks, delay): + led = machine.Pin("LED", machine.Pin.OUT) + i = 0 + while i is not blinks: + led.off() + time.sleep(delay /2) + led.on() + time.sleep(delay /2) + i = i + 1 diff --git a/pico_w/Gameberry/modules/characterSets.py b/pico_w/Gameberry/modules/characterSets.py new file mode 100644 index 0000000..67c0c83 --- /dev/null +++ b/pico_w/Gameberry/modules/characterSets.py @@ -0,0 +1,89 @@ +def default(lcd): + degree_char = [ + 0b00111, + 0b00101, + 0b00111, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000 + ] + heart_char = [ + 0b00000, + 0b01010, + 0b11111, + 0b11111, + 0b01110, + 0b00100, + 0b00000, + 0b00000 + ] + sadFace_char = [ + 0b00000, + 0b01010, + 0b00000, + 0b01110, + 0b10001, + 0b00000, + 0b00000, + 0b00000 + ] + happyFace_char = [ + 0b00000, + 0b01010, + 0b00000, + 0b10001, + 0b01110, + 0b00000, + 0b00000, + 0b00000 + ] + checkmark_char = [ + 0b00000, + 0b00001, + 0b00010, + 0b10100, + 0b01000, + 0b00000, + 0b00000, + 0b00000 + ] + x_char = [ + 0b00000, + 0b00000, + 0b01010, + 0b00100, + 0b01010, + 0b00000, + 0b00000, + 0b00000 + ] + battery = [ + 0b00000, + 0b00100, + 0b01110, + 0b01010, + 0b01010, + 0b01010, + 0b01110, + 0b00000 + ] + full_char = [ + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 + ] + lcd.create_custom_char(0,degree_char) + lcd.create_custom_char(1,heart_char) + lcd.create_custom_char(2,sadFace_char) + lcd.create_custom_char(3,happyFace_char) + lcd.create_custom_char(4,checkmark_char) + lcd.create_custom_char(5,x_char) + lcd.create_custom_char(6,battery) + lcd.create_custom_char(7,full_char) \ No newline at end of file diff --git a/pico_w/Gameberry/modules/customExceptions.py b/pico_w/Gameberry/modules/customExceptions.py new file mode 100644 index 0000000..54c9916 --- /dev/null +++ b/pico_w/Gameberry/modules/customExceptions.py @@ -0,0 +1,44 @@ +# Files +class FileCopyError(Exception): + pass +class FileReadError(Exception): + pass + +# Data +class DataVerificationError(Exception): + pass + +# Translations +class TranslationNotFound(Exception): + pass + +# Defaults +class DefaultsNotFound(Exception): + pass + + +# Wifi +class WifiNotConnected(Exception): + pass + +# POST +class LcdDisplayError(Exception): + pass + +class FileReadWriteError(Exception): + pass + +# Error screen +def ShowErrorScreen(lcd): + lcd.setRGB(255,0,0) + lcd.setCursor(0,0) + lcd.write(2) + lcd.setCursor(0,1) + lcd.printout("Connect debugger") + +def ShowErrorScreen_with_code(lcd, code): + lcd.setRGB(255,0,0) + lcd.setCursor(0,0) + lcd.write(2) + lcd.setCursor(0,1) + lcd.printout(code) \ No newline at end of file diff --git a/pico_w/Gameberry/modules/files.py b/pico_w/Gameberry/modules/files.py new file mode 100644 index 0000000..1ec0273 --- /dev/null +++ b/pico_w/Gameberry/modules/files.py @@ -0,0 +1,25 @@ +import os +import uos + +def exist(filename): + try: + os.stat(filename) + return True + except OSError: + return False + +def copy(source, target): + try: + if os.stat(target)[0] & 0x4000: # is directory + target = target.rstrip("/") + "/" + source + except OSError: + pass + with open(source, "rb") as source: + with open(target, "wb") as target: + while True: + l = source.read(512) + if not l: break + target.write(l) + +def create_folder(name): + uos.mkdir(name) \ No newline at end of file diff --git a/pico_w/Gameberry/modules/gameSystemMenu.py b/pico_w/Gameberry/modules/gameSystemMenu.py new file mode 100644 index 0000000..4d4b745 --- /dev/null +++ b/pico_w/Gameberry/modules/gameSystemMenu.py @@ -0,0 +1,69 @@ +import time +import machine +from machine import Pin +import modules.json as json +import gc + +button1 = Pin(3, Pin.IN, Pin.PULL_UP) # First button (GPIO3) +button2 = Pin(2, Pin.IN, Pin.PULL_UP) # Second button (GPIO2) +home = Pin(15, Pin.IN, Pin.PULL_UP) # Home +btn1state = 0 +btn2state = 0 +homestate = 0 + +def show(lcd): + global btn1state + global btn2state + global homestate + btn1state = 0 + btn2state = 0 + homestate = 0 + gc.collect() + print("Showing system menu") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Loading data!") + lcd.setCursor(0,1) + lcd.printout("Please wait...") + data = json.read("/settings.json") + time.sleep(0.2) + _temp_lcd_brightness = data.get('lcd_brightness') + lcd.setRGB(_temp_lcd_brightness, _temp_lcd_brightness, _temp_lcd_brightness) + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("1. Sleep 2. Hide") + lcd.setCursor(0,1) + lcd.printout("Home: Exit") + menuOpen = True + sleep = False + while menuOpen == True: + time.sleep(0.05) + if button1.value() == 0 and btn1state == 1: + lcd.clear() + lcd.setRGB(0,0,0) + sleep = True + menuOpen = False + while sleep == True: + time.sleep(0.5) + if home.value() == 0: + sleep = False + show(lcd) + return + if button2.value() == 0 and btn1state == 1: + gc.collect() + lcd.clear() + menuOpen = False + return + if home.value() == 0 and btn1state == 1: + gc.collect() + machine.soft_reset() + if home.value() == 1: + homestate = 1 + if button1.value() == 1: + btn1state = 1 + if button2.value() == 1: + btn2state = 1 + + + + diff --git a/pico_w/Gameberry/modules/ina219.py b/pico_w/Gameberry/modules/ina219.py new file mode 100644 index 0000000..e5ecb2a --- /dev/null +++ b/pico_w/Gameberry/modules/ina219.py @@ -0,0 +1,79 @@ +from machine import I2C +import time + +# INA219 default address +INA219_ADDRESS = 0x40 + +# Registers +REG_CONFIG = 0x00 +REG_SHUNTVOLTAGE = 0x01 +REG_BUSVOLTAGE = 0x02 +REG_POWER = 0x03 +REG_CURRENT = 0x04 +REG_CALIBRATION = 0x05 + +# Config register bits +CONFIG_RESET = 0x8000 +CONFIG_BVOLTAGERANGE_32V = 0x2000 +CONFIG_GAIN_8_320MV = 0x1800 +CONFIG_BADCRES_12BIT = 0x0180 +CONFIG_SADCRES_12BIT_1S_532US = 0x0078 +CONFIG_MODE_SANDBVOLT_CONTINUOUS = 0x0007 + +# Calibration value for a 0.1 ohm shunt resistor and max current of 3.2A +CALIBRATION_VALUE = 4096 + +# Constants +SHUNT_RESISTANCE = 0.1 # Ohms +CURRENT_LSB = 0.1 # mA per bit + +class INA219: + def __init__(self, shunt_ohms, i2c, addr=INA219_ADDRESS): + self.i2c = i2c + self.addr = addr + self.shunt_ohms = shunt_ohms + self.calibration_value = CALIBRATION_VALUE + self.configure() + + def write_register(self, reg, value): + data = [(value >> 8) & 0xFF, value & 0xFF] + self.i2c.writeto_mem(self.addr, reg, bytes(data)) + + def read_register(self, reg): + data = self.i2c.readfrom_mem(self.addr, reg, 2) + return (data[0] << 8) | data[1] + + def configure(self): + # Reset the INA219 + self.write_register(REG_CONFIG, CONFIG_RESET) + time.sleep(0.1) + + config = (CONFIG_BVOLTAGERANGE_32V | CONFIG_GAIN_8_320MV | + CONFIG_BADCRES_12BIT | CONFIG_SADCRES_12BIT_1S_532US | + CONFIG_MODE_SANDBVOLT_CONTINUOUS) + self.write_register(REG_CONFIG, config) + + # Set calibration + self.write_register(REG_CALIBRATION, self.calibration_value) + + def shunt_voltage(self): + value = self.read_register(REG_SHUNTVOLTAGE) + if value > 32767: + value -= 65536 + return value * 0.01 # mV + + def bus_voltage(self): + value = self.read_register(REG_BUSVOLTAGE) + return (value >> 3) * 0.004 # V + # V + + def current(self): + self.write_register(REG_CALIBRATION, self.calibration_value) + value = self.read_register(REG_CURRENT) + if value > 32767: + value -= 65536 + return value * CURRENT_LSB # mA + + def power(self): + value = self.read_register(REG_POWER) + return value * 20 # mW diff --git a/pico_w/Gameberry/modules/json.py b/pico_w/Gameberry/modules/json.py new file mode 100644 index 0000000..8fdd076 --- /dev/null +++ b/pico_w/Gameberry/modules/json.py @@ -0,0 +1,13 @@ +import ujson as json + +def read(filename): + with open(filename, 'r') as file: + data = json.load(file) + return data + +def write(filename, data): + with open(filename, 'wb') as file: + json.dump(data, file) + +def read_from_string(data): + return json.loads(data) \ No newline at end of file diff --git a/pico_w/Gameberry/modules/math.py b/pico_w/Gameberry/modules/math.py new file mode 100644 index 0000000..9a692c1 --- /dev/null +++ b/pico_w/Gameberry/modules/math.py @@ -0,0 +1,5 @@ +def is_positive(number): + if number > 0: + True + elif number < 0: + return False \ No newline at end of file diff --git a/pico_w/Gameberry/modules/ntp.py b/pico_w/Gameberry/modules/ntp.py new file mode 100644 index 0000000..bd4e489 --- /dev/null +++ b/pico_w/Gameberry/modules/ntp.py @@ -0,0 +1,10 @@ +import ntptime + +def sync(wlan): + try: + while not wlan.isconnected(): + pass + ntptime.settime() + except: + print("Error") + diff --git a/pico_w/Gameberry/modules/requests.py b/pico_w/Gameberry/modules/requests.py new file mode 100644 index 0000000..a28da29 --- /dev/null +++ b/pico_w/Gameberry/modules/requests.py @@ -0,0 +1,13 @@ +import urequests +import gc + +def GET(url): + gc.collect() + response = urequests.get(url) + return response + +def POST(url, data): + gc.collect() + headers = {'Content-Type': 'application/json'} + response = urequests.post(url, data=data, headers=headers) + return response diff --git a/pico_w/Gameberry/modules/saveDataManager.py b/pico_w/Gameberry/modules/saveDataManager.py new file mode 100644 index 0000000..9109509 --- /dev/null +++ b/pico_w/Gameberry/modules/saveDataManager.py @@ -0,0 +1,69 @@ +import modules.json as json +import modules.files as files +import utime as time + +def load(): + start = time.time() + print() + print("[SaveDataManager] Loading save data:") + if files.exist("/game/game_info.json"): + print(" Reading game info...") + gameInfo = json.read("/game/game_info.json") + saveDataInfo = gameInfo['saveDataManager'] + print(" Game info:") + print(" Game ID: "+ gameInfo['id']) + print(" Game name: " + gameInfo['name']) + print(" Default save data file: "+saveDataInfo["default"]) + if saveDataInfo["format"] == "json": + print("Checking if save data exists...") + if files.exist("/savedata/"+gameInfo["id"]+".json"): + print("Save data exists") + else: + print("Copying default save data ") + files.copy("/game/"+saveDataInfo["default"], "/savedata/"+gameInfo["id"]+".json") + savefile = json.read("/savedata/"+gameInfo["id"]+".json") + time_elapsed = start - time.time() + print("Save data read in "+str(time_elapsed)+"s.") + print("") + return savefile + else: + print(" Unsupported file format!") + print("") + return None + else: + print(" Game info not found! Cannot load game data!") + print("") + return None + +def save(data): + start = time.time() + print() + print("[SaveDataManager] Saving save data:") + if files.exist("/game/game_info.json"): + print(" Reading game info...") + gameInfo = json.read("/game/game_info.json") + saveDataInfo = gameInfo['saveDataManager'] + print(" Game info:") + print(" Game ID: "+ gameInfo['id']) + print(" Game name: " + gameInfo['name']) + print(" Default save data file: "+saveDataInfo["default"]) + if saveDataInfo["format"] == "json": + print("Checking if save data exists...") + if files.exist("/savedata/"+gameInfo["id"]+".json"): + print("Save data exists") + else: + print("Copying default save data ") + files.copy("/game/"+saveDataInfo["default"], "/savedata/"+gameInfo["id"]+".json") + savefile = json.write("/savedata/"+gameInfo["id"]+".json", data) + time_elapsed = start - time.time() + print("Save data saved in "+str(time_elapsed)+"s.") + print("") + return 0 + else: + print(" Unsupported file format!") + print("") + return 1 + else: + print(" Game info not found! Cannot load game data!") + print("") + return 1 \ No newline at end of file diff --git a/pico_w/Gameberry/modules/sd.py b/pico_w/Gameberry/modules/sd.py new file mode 100644 index 0000000..b6a1c10 --- /dev/null +++ b/pico_w/Gameberry/modules/sd.py @@ -0,0 +1,68 @@ +import machine +import modules.sdcard as sdcard +import uos +import gc + +sd = None +started = False +mounted = False +mountPoint = "" + +def mount(path): + global sd + global started + global mounted + global mountPoint + print("Mounting SD Card...") + if started == False: + start() + if mounted == False: + vfs = uos.VfsFat(sd) + uos.mount(vfs, path) + mounted = True + mountPoint = path + print("Mounted SD Card!") + print("Path of SD: "+path) + +def unmount(): + global sd + global started + global mounted + global mountPoint + print("Unmounting SD Card...") + if mounted == True: + uos.unmount(mountPoint) + mounted = False + mountPoint = "" + print("Unmounted SD Card!") + +def start(): + global sd + global started + print("Starting SD Card...") + print("Initializing SPI...") + cs = machine.Pin(13, machine.Pin.OUT) + spi = machine.SPI(1, + baudrate=1000000, + polarity=0, + phase=0, + bits=8, + firstbit=machine.SPI.MSB, + sck=machine.Pin(10), + mosi=machine.Pin(11), + miso=machine.Pin(12)) + print("Initializing SD Card...") + sd = sdcard.SDCard(spi, cs) + started = True + print("Started SD Card!") + +def stop(): + global sd + if started == True: + print("Stopping SD card...") + unmount() + sd = None + gc.collect() + print("SD Card stopped!") + + \ No newline at end of file diff --git a/pico_w/Gameberry/modules/sdcard.py b/pico_w/Gameberry/modules/sdcard.py new file mode 100644 index 0000000..c141ce2 --- /dev/null +++ b/pico_w/Gameberry/modules/sdcard.py @@ -0,0 +1,241 @@ +from micropython import const +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +# R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +# R1_COM_CRC_ERROR = const(1 << 3) +# R1_ERASE_SEQUENCE_ERROR = const(1 << 4) +# R1_ADDRESS_ERROR = const(1 << 5) +# R1_PARAMETER_ERROR = const(1 << 6) +_TOKEN_CMD25 = const(0xFC) +_TOKEN_STOP_TRAN = const(0xFD) +_TOKEN_DATA = const(0xFE) + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + self.cs.init(self.cs.OUT, value=1) + self.init_spi(100000) + for i in range(16): + self.spi.write(b"\xff") + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + self.cdv = 512 + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) + ocr = self.tokenbuf[0] + if not ocr & 0x40: + + self.cdv = 512 + else: + + self.cdv = 1 + + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + self.cs(1) + raise OSError(5) + self.readinto(buf) + else: + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + self.cs(1) + raise OSError(5) + offset = 0 + mv = memoryview(buf) + while nblocks: + + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) + + def writeblocks(self, block_num, buf): + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) + + self.write(_TOKEN_DATA, buf) + else: + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: + return self.sectors + if op == 5: + return 512 + def is_present(self): + try: + response = self.cmd(0, 0, 0x95) + if response == _R1_IDLE_STATE: + return True + else: + return False + except OSError: + return False \ No newline at end of file diff --git a/pico_w/Gameberry/modules/time.py b/pico_w/Gameberry/modules/time.py new file mode 100644 index 0000000..bb43ed4 --- /dev/null +++ b/pico_w/Gameberry/modules/time.py @@ -0,0 +1,16 @@ +import utime +import modules.json as json + +data = json.read("/settings.json") + +def get_timezoned(): + time1=utime.time() + if data.get("timezone").get("timezone_on_minus") < 0: + temp = data.get("timezone").get("timezone") * 3600 + temp2 = temp * 2 + timeminus = temp - temp2 + final = time1 + timeminus + return final + else: + temp = 3600 * data.get("timezone").get("timezone") + return time1 + temp diff --git a/pico_w/Gameberry/modules/translations.py b/pico_w/Gameberry/modules/translations.py new file mode 100644 index 0000000..15554cf --- /dev/null +++ b/pico_w/Gameberry/modules/translations.py @@ -0,0 +1,31 @@ +import modules.json as json +import modules.files as files +import modules.customExceptions as exceptions +import network +import modules.requests as requests +import gc + +translation = None + +def load(lang): + global translation + translationFile = "/translations/"+lang+".json" + if files.exist(translationFile): + translation = json.read(translationFile) + print("Translation loaded: "+lang+" "+translation["info"]["name"]) + else: + raise exceptions.TranslationNotFound("Translation '"+lang+"' not found!") + +def loadExternal(path): + global translation + translationFile = path + if files.exist(translationFile): + translation = json.read(translationFile) + + +def get(thing1, thing2): + if translation == None: + load("en") + return translation["translation"][thing1][thing2] + else: + return translation["translation"][thing1][thing2] \ No newline at end of file diff --git a/pico_w/Gameberry/plugins/octolib.py b/pico_w/Gameberry/plugins/octolib.py new file mode 100644 index 0000000..c7aa490 --- /dev/null +++ b/pico_w/Gameberry/plugins/octolib.py @@ -0,0 +1,269 @@ +import modules.requests as requests +import ujson +import gc +import urequests + +octoPrintUrl = "" +octoApiKey = "" + +def setOctoPrintUrl(url): + global octoPrintUrl + octoPrintUrl = url + +def setOctoPrintApiKey(apiKey): + global octoApiKey + octoApiKey = apiKey + + +def appKeysProbe(): + global octoPrintUrl + request = requests.GET(octoPrintUrl + "/plugin/appkeys/probe") + if request.status_code == 204: + request.close() + return True + else: + request.close() + return False + +def appKeysRequest(appName): + global octoPrintUrl + post_data = ujson.dumps({"app": appName}) + request = requests.POST(octoPrintUrl + "/plugin/appkeys/request", post_data) + if request.status_code == 201: + apptoken = request.json()["app_token"] + request.close() + accepted = False + checks = 0 + token = "" + print("Waiting for users choice") + while accepted == False and checks < 60: + gc.collect() + rq = requests.GET(octoPrintUrl + "/plugin/appkeys/request/"+apptoken) + if rq.status_code == 200: + token = rq.json()["api_key"] + accepted = True + elif rq.status_code == 404: + checks == 30 + print("Error 404") + rq.close() + checks = checks + 1 + return token + +def getPrinterProfiles(): + rq = requestGet("/api/printerprofiles") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return json + else: + print("Status code other than 200") + gc.collect() + return "" + +def getPrinterProfile(name): + rq = requestGet("/api/printerprofiles") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + try: + return json["profiles"][name] + except: + print("Cannot get print profile "+ name) + return "" + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def testApiKey(): + rq = requestGet("/api/server") + code = rq.status_code + rq.close() + if code == 200: + return True + else: + return False + +def getTemps(): + rq = requestGet("/api/printer?exclude=state,sd") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return json + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def getState(): + rq = requestGet("/api/printer?exclude=state,temperature") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return json + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def getConnetion(): + rq = requestGet("/api/connection") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return json + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def connect(): + post_data = ujson.dumps({"command": "connect"}) + rq = requestPost("/api/connection", post_data) + if rq.status_code == 204: + rq.close() + return True + else: + rq.close() + return False + +def disconnect(): + post_data = ujson.dumps({"command": "disconnect"}) + rq = requestPost("/api/connection", post_data) + if rq.status_code == 204: + rq.close() + return True + else: + rq.close() + return False + +def getSdCardState(): + rq = requestGet("/api/printer/sd") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return sdStateResponse(json["ready"]) + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def apiVersion(): + rq = requestGet("/api/version") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return apiVersionResponse(json["api"],json["server"],json["text"]) + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return None + +def getSystemCommands(): + rq = requestGet("/api/system/commands") + code = rq.status_code + json = rq.json() + rq.close() + if code == 200: + gc.collect() + return json + else: + print("Status code: "+str(code)+"\n"+str(json)) + gc.collect() + return "" + +def executeSystemCommand(source, action): + post_data = ujson.dumps({"command": "connect"}) + rq = requestPost("/api/connection", post_data) + if rq.status_code == 204: + rq.close() + return True + elif rq.status_code == 404: + print("command not found") + rq.close() + return False + else: + rq.close() + return False + +def setToolheadTemperature(temp, toolheadNumber = 0): + post_data = ujson.dumps({"command": "target", "targets": {"tool"+str(toolheadNumber): temp}}) + rq = requestPost("/api/printer/tool", post_data) + if rq.status_code == 204: + rq.close() + return True + elif rq.status_code == 404: + print("command not found") + rq.close() + return False + else: + rq.close() + return False + +def setBedTemperature(temp): + post_data = ujson.dumps({"command": "target", "target": temp}) + rq = requestPost("/api/printer/bed", post_data) + if rq.status_code == 204: + rq.close() + return True + elif rq.status_code == 404: + print("command not found") + rq.close() + return False + else: + rq.close() + return False + +def setChamberTemperature(temp): + post_data = ujson.dumps({"command": "target", "target": temp}) + rq = requestPost("/api/printer/chamber", post_data) + if rq.status_code == 204: + rq.close() + return True + elif rq.status_code == 404: + print("command not found") + rq.close() + return False + else: + rq.close() + return False + +def requestPost(endpoint, data): + global octoApiKey + global octoPrintUrl + gc.collect() + headers = {'Content-Type': 'application/json', 'X-Api-Key': octoApiKey} + response = urequests.post(octoPrintUrl + endpoint, data=data, headers=headers) + return response + +def requestGet(endpoint): + global octoApiKey + global octoPrintUrl + gc.collect() + headers = {'X-Api-Key': octoApiKey} + response = urequests.get(octoPrintUrl + endpoint, headers=headers) + return response + +class apiVersionResponse: + def __init__(self, api,server,text): + self.api = api + self.server = server + self.text = text + +class sdStateResponse: + def __init__(self, ready): + self.ready = ready \ No newline at end of file diff --git a/pico_w/Gameberry/plugins/octoprint.py b/pico_w/Gameberry/plugins/octoprint.py new file mode 100644 index 0000000..1cc2fea --- /dev/null +++ b/pico_w/Gameberry/plugins/octoprint.py @@ -0,0 +1,207 @@ +import modules.json as json +import network +import time +import machine +import plugins.octolib as octo +import gc +from micropython import const +import ujson +import modules.files as files +from machine import Pin + +updates = 0 + +curr = 0 + +_SKIP_PROFILE_CHECK = const(False) # Set values under this + +heatedChamber = False +heatedBed = True + +button1 = Pin(3, Pin.IN, Pin.PULL_UP) # First button (GPIO3) +button2 = Pin(2, Pin.IN, Pin.PULL_UP) # Second button (GPIO2) +home = Pin(15, Pin.IN, Pin.PULL_UP) # Home button (GPIO15) +button1state = 1 +button2state = 1 +homestate = 1 + +config = None + +def start(lcd): + global config + keyTested = False + lcd.clear() + wlan = network.WLAN(network.STA_IF) + if wlan.isconnected() == False: + lcd.setCursor(0,0) + lcd.printout("Wi-Fi not") + lcd.setCursor(0,1) + lcd.printout("connected") + time.sleep(1) + machine.soft_reset() + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("OctoPrint Remote") + lcd.setCursor(0,1) + lcd.printout("Kitki30") + time.sleep(0.25) + print("Loading OctoPrint app") + print("Collect trash...") + gc.collect() + print("Read config") + config = json.read("/plugins/octoprint-config.json") + print("Check url") + if config["url"] == "": + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("URL not set") + time.sleep(1) + machine.soft_reset() + else: + octo.setOctoPrintUrl(config["url"]) + print("Check apikey") + if config["apiKey"] == "": + print("No apikey set checking for appkeys plugin") + if octo.appKeysProbe() == True: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Requesting ApiKe") + lcd.setCursor(0,1) + lcd.printout("y check Panel") + token = octo.appKeysRequest("OctoPrint Remote for GameBerry") + if token == "": + print("Chosen no or timed out") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("set apiKey") + time.sleep(1) + machine.soft_reset() + else: + octo.setOctoPrintApiKey(token) + if octo.testApiKey == False: + print("Bad api key") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("set apiKey") + time.sleep(1) + machine.soft_reset() + else: + keyTested = True + config["apiKey"] = token + json.write("/plugins/octoprint-config.json", config) + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Restarting...") + f = open('/startOptions.gameberry', 'w') + f.write('octo-plugin') + f.close() + time.sleep(1) + machine.soft_reset() + + else: + print("No appkeys plugin detected") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("apiKey not set") + time.sleep(1) + machine.soft_reset() + octo.setOctoPrintApiKey(config["apiKey"]) + if octo.testApiKey == False: + print("Bad api key") + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("set apiKey") + config["apiKey"] = "" + json.write("/plugins/octoprint-config.json", config) + time.sleep(1) + machine.soft_reset() + else: + setup(lcd) + + +def setup(lcd): + global heatedBed + global heatedChamber + gc.collect() + if _SKIP_PROFILE_CHECK == False: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Reading printer") + lcd.setCursor(0,1) + lcd.printout("info...") + profile = octo.getPrinterProfile("_default") + if profile == "": + print("Cannot get print profile info looking for cache!") + if files.exist("/plugins/octo-cache.cache"): + cache = json.read("/plugins/octo-cache.cache") + heatedChamber = cache["heatedChamber"] + heatedBed = cache["heatedBed"] + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Cannot get print") + lcd.setCursor(0,1) + lcd.printout("profile info!") + time.sleep(1) + machine.soft_reset() + else: + print("Profile "+profile["id"]+"\nName: "+profile["name"]+"\nPrinter: "+profile["model"]+"\nDefault: "+str(profile["default"])+"\nCurrent: "+str(profile["current"])+"\nHeated Bed: "+str(profile["heatedBed"])+"\nHeated Chamber: "+str(profile["heatedChamber"])) + heatedChamber = profile["heatedChamber"] + heatedBed = profile["heatedBed"] + SaveCache(heatedBed, heatedChamber) + main(lcd) + else: + main(lcd) + +def SaveCache(heatedBed, heatedChamber): + json.write("/plugins/octo-cache.cache", ujson.dumps({"heatedBed": heatedBed, "heatedChamber": heatedChamber})) + +def basicTemps(lcd): + global curr + curr = 0 + temp = octo.getTemps() + if heatedBed == True: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Bed: "+str(round(temp["temperature"]["bed"]["actual"]))) + lcd.write(0) + lcd.printout("C") + lcd.setCursor(0,1) + lcd.printout("Tool: "+str(round(temp["temperature"]["tool0"]["actual"]))) + lcd.write(0) + lcd.printout("C") + else: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Tool: "+str(round(temp["temperature"]["tool0"]["actual"]))) + lcd.write(0) + lcd.printout("C") + if heatedChamber == True: + lcd.setCursor(0,1) + lcd.printout("Chamber: "+str(round(temp["temperature"]["tool0"]["actual"]))) + lcd.write(0) + lcd.printout("C") + +def chamberTemp(lcd): + global curr + curr = 1 + temp = octo.getTemps() + lcd.clear() + lcd.setCursor(0,1) + lcd.printout("Chamber: "+str(round(temp["temperature"]["chamber"]["actual"]))) + lcd.write(0) + lcd.printout("C") + +def main(lcd): + global curr + global updates + basicTemps(lcd) + while True: + if button2.value() == 0 and button2state == 1: + if curr == 0: + if heatedChamber == True: + chamberTemp(lcd) + if curr == 1: + basicTemps(lcd) + else: + button2state = 1 + \ No newline at end of file diff --git a/pico_w/Gameberry/translations/en.json b/pico_w/Gameberry/translations/en.json new file mode 100644 index 0000000..10cae93 --- /dev/null +++ b/pico_w/Gameberry/translations/en.json @@ -0,0 +1,39 @@ +{ + "info": { + "name": "English", + "author": "Kitki30", + "description": "Default GameBerry Language.", + "compatible_with": 0.6, + "version": 1.2 + }, + "translation": { + "debugger": { + "gameberry_on": "on", + "machine_freq": "Machine frequency", + "settings_exist": "Settings exist!", + "savedata_exist": "Savedata exist!", + "waiting_one_second": "Waiting one second" + }, + "wifi": { + "connecting_to": "Connecting to", + "connection_fail": "Connection Fail", + "ap_not_found": "AP not found", + "wrong_password": "Wrong password" + }, + "global": { + "settings": "Settings", + "game": "Game", + "error": "Error", + "exit": "Exit" + }, + "rtc": { + "debugger_rtc": "Sync rtc clock...", + "setting_clock": "Setting clock..." + }, + "menu": { + "play_next": "1. Play 2. Next", + "ok_next": "1. OK 2. Next", + "exit_next": "1. Exit 2. Next" + } + } +} \ No newline at end of file diff --git a/pico_w/Gameberry/translations/pl.json b/pico_w/Gameberry/translations/pl.json new file mode 100644 index 0000000..4408bb8 --- /dev/null +++ b/pico_w/Gameberry/translations/pl.json @@ -0,0 +1,39 @@ +{ + "info": { + "name": "Polski", + "author": "Kitki30", + "description": "Język polski dla GameBerry. Nie ma polskich znaków ponieważ ekran LCD1602 ich nie obsługuje!", + "compatible_with": 0.6, + "version": 1.0 + }, + "translation": { + "debugger": { + "gameberry_on": "na", + "machine_freq": "Częstotliwość procesora", + "settings_exist": "Ustawienia istnieją!", + "savedata_exist": "Dane zapisów instnieją!", + "waiting_one_second": "Czekam jendą sekunde!" + }, + "wifi": { + "connecting_to": "Laczenie z", + "connection_fail": "Blad laczenia", + "ap_not_found": "AP nie znalez.", + "wrong_password": "Zle haslo" + }, + "global": { + "settings": "Ustawienia", + "game": "Gra", + "error": "Blad", + "exit": "Wyjdz" + }, + "rtc": { + "debugger_rtc": "Synchronizacja RTC...", + "setting_clock": "Ustawiam zegar.." + }, + "menu": { + "play_next": "1. Graj 2. Nast.", + "ok_next": "1. OK 2. Nast.", + "exit_next": "1. OK 2. Nast." + } + } +} \ No newline at end of file diff --git a/pico_w/Gameberry/voltage_meter_mode.py b/pico_w/Gameberry/voltage_meter_mode.py new file mode 100644 index 0000000..bfa5435 --- /dev/null +++ b/pico_w/Gameberry/voltage_meter_mode.py @@ -0,0 +1,15 @@ +import modules.ina219 +import modules.RGB1602 as l +import time +from machine import I2C, Pin + +lcd = l.RGB1602(16,2) +i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000) +SHUNT_OHMS = 0.1 +ina = modules.ina219.INA219(SHUNT_OHMS, i2c) +while True: + lcd.setCursor(0,0) + lcd.printout(str(ina.current())) + lcd.setCursor(0,1) + lcd.printout(str(ina.bus_voltage())) + time.sleep(0.1) \ No newline at end of file diff --git a/pico_w/Gameberry/webSetup/webSetup.py b/pico_w/Gameberry/webSetup/webSetup.py new file mode 100644 index 0000000..50c33e1 --- /dev/null +++ b/pico_w/Gameberry/webSetup/webSetup.py @@ -0,0 +1,68 @@ +import network +import machine +import gc +import usocket as socket +import ujson + + +ALLOW_TESTS = True + +routes = {} + +def add_route(path, method, handler): + if path not in routes: + routes[path] = {} + routes[path][method] = handler + +def handle_request(path, method, body): + if path in routes and method in routes[path]: + return routes[path][method](body) + else: + return 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\n404 not found.' + +def test_h(_): + global ALLOW_TESTS + if ALLOW_TESTS == True: + return 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n' + "Test" + + +def launch(): + gc.collect() + print("Launching setup...") + ap = network.WLAN(network.AP_IF) + ap.config(essid='Gameberry-Setup') + ap.active(True) + while not ap.active(): + pass + print("Connect to hotspot:\nSSID: Gameberry-setup") + print('Network config:', ap.ifconfig()) + + gc.collect() + add_route("/test", "GET", test_h) + + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + s = socket.socket() + s.bind(addr) + s.listen(1) + + print('Listening on', addr) + + while True: + cl, addr = s.accept() + print('Client connected ', addr) + request = b"" + while True: + data = cl.recv(1024) + if not data: + break + request += data + request_str = request.decode() + print("Request:", request_str) + try: + method, path, _ = request_str.split(' ', 2) + headers, body = request_str.split('\r\n\r\n', 1) + except ValueError: + method, path, body = 'GET', '/', '' + response = handle_request(path, method, body) + cl.send(response) + cl.close() \ No newline at end of file diff --git a/pico_w/README.MD b/pico_w/README.MD new file mode 100644 index 0000000..d012119 --- /dev/null +++ b/pico_w/README.MD @@ -0,0 +1,28 @@ +# Gameberry for Raspberry Pi Pico W + +## Installation Guide + +### Required hardware: +- Waveshare RGB1602 LCD Display +- 3 buttons (tact switch), 1 - Home Button and 2 button in other color than Home button +- Raspberry Pi Pico W +- Buzzer + +This hardware is required for basic functions of Gameberry + +### Optional hardware: +- SD / micro SD card breakout (Used for saving games (Save data can also be saved on internal storage), Booting Gameberry from SD card, Saving settings and more) +- Battery (For powering your Pico without cable, needs charger) +- INA219 (Used for checking battery voltage, current and power (not required even when you have battery)) + +### Installation: +1. Download latest micropython [here](https://micropython.org/download/rp2-pico-w/rp2-pico-w-latest.uf2) +3. Hold BOOTSEL button and connect your Pico to PC then copy micropython uf2 file to RPI-RP2 volume +4. Download and install thonny on your pc +5. Download install.py file from Github +6. Set wifi password and ssid in the script +7. Run script +> [!WARNING] +> Install.py script will delete every file on the flash of device! + +If installation completed without errors Pico should reboot by it self and \ No newline at end of file diff --git a/pico_w/download_list.txt b/pico_w/download_list.txt new file mode 100644 index 0000000..666a9ae --- /dev/null +++ b/pico_w/download_list.txt @@ -0,0 +1,115 @@ +Kitki30-Gameberry-Download-List-File +version 1.0 +START +message +Welcome to Gameberry Download List File +message +Installation can take from 15 seconds to few minutes device will restart +message +after installation is successfull! +message +Please check Shell for errors! +time +2.5 +log-message +------ Installation started ------ +create-device-config +download +main.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/main.py +download +gameberry.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/gameberry.py +download +voltage_meter_mode.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/voltage_meter_mode.py +download +boot_config.json +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/boot_config.json +folder +default +download +default/settings_default.json +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/default/settings_default.json +folder +modules +download +modules/RGB1602.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/RGB1602.py +download +modules/basicThread.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/basicThread.py +download +modules/battery.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/battery.py +download +modules/blinker.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/blinker.py +download +modules/characterSets.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/characterSets.py +download +modules/customExceptions.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/customExceptions.py +download +modules/files.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/files.py +download +modules/gameSystemMenu.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/gameSystemMenu.py +download +modules/ina219.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/ina219.py +download +modules/json.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/json.py +download +modules/math.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/math.py +download +modules/ntp.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/ntp.py +download +modules/requests.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/requests.py +download +modules/saveDataManager.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/saveDataManager.py +download +modules/sd.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/sd.py +download +modules/sdcard.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/sdcard.py +download +modules/time.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/time.py +download +modules/translations.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/modules/translations.py +folder +plugins +download +plugins/octolib.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/plugins/octolib.py +download +plugins/octoprint.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/plugins/octoprint.py +folder +translations +download +translations/pl.json +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/translations/pl.json +download +translations/en.json +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/translations/en.json +folder +webSetup +download +webSetup/webSetup.py +https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/Gameberry/webSetup/webSetup.py +log-message +------ Installation started ------ +comment +See how to use Download lists here: https://github.com/Kitki30/GameBerry/blob/main/download_list_guide.md +END \ No newline at end of file diff --git a/pico_w/install.py b/pico_w/install.py new file mode 100644 index 0000000..39c73a5 --- /dev/null +++ b/pico_w/install.py @@ -0,0 +1,300 @@ +# Change settings here + +# Set your Wifi here +WiFi_SSID = "" +WiFi_PASSWORD = "" + +# Set gameberry device config here +INA219 = True +SD_READER = True + +# Don't change anything under than line unless you know what you are doing! + +# Download list URL +download_list_url = "https://raw.githubusercontent.com/Kitki30/GameBerry/main/pico_w/download_list.txt" +download_list_path = "/list.txt" + +# Force not to format flash +force_not_to_format_flash = False + +# Log Path +log_path = "/install_log.log" + +# Imports +import ujson +import urequests +import gc +import network +import time +import os +import uos +import machine + +def log(log): + with open(log_path, "a") as file: + file.write(str("\n"+log)) + +def read_json(filename): + with open(filename, 'r') as file: + data = ujson.load(file) + return data + +def write_json(filename, data): + with open(filename, 'wb') as file: + ujson.dump(data, file) + +def write_device_config(ina, sd): + write_json("/device_confg.json", ujson.dumps({"INA219": ina, "SD_READER": sd})) + +def GET_request(url): + log("GC Collect...") + gc.collect() + log("Make GET request...") + response = urequests.get(url) + log("Made GET request...") + return response + +def download_file(url, filename): + log("Making GET request for File download") + response = GET_request(url) + + if response.status_code == 200: + log("Writing content of request to file") + with open(filename, 'wb') as f: + f.write(response.content) + log("Closing response") + response.close() + return True + else: + log("Error, status code: "+response.status_code) + log("Closing response") + response.close() + return False + +def readline(line_number, filename): + log("Reading line " + str(line_number) + " of file " + filename) + with open(filename, 'r') as file: + for current_line_number, line in enumerate(file, start=1): + if current_line_number == line_number: + return line.strip() + return None + +def remove_item(path): + if os.stat(path)[0] & 0x4000: + for item in os.listdir(path): + remove_item(path + "/" + item) + os.rmdir(path) + else: + os.remove(path) + +def format_flash(): + files = os.listdir() + for file in files: + if file == log_path: + log("Deleting: " + str(file)) + print("Deleting " + str(file)) + remove_item(file) + +def download_list(url): + return download_file(download_list_url, download_list_path) + +def variables(text): + x = text.replace("${machine_name}", str(uos.uname().machine)).replace("${log_path}", log_path) + return x + +if log_path in os.listdir(): + os.remove(log_path) +log("Starting installer") +log("Machine name: "+str(uos.uname().machine)) +print("Machine name: "+str(uos.uname().machine)) +print("\033[94mWelcome to GameBerry installer by Kitki30\033[0m") +time.sleep(0.1) +log("Showing warning") +print("") +print("\033[91mWARNING: THIS INSTALLER WILL DELETE EVERY FILE ON\033[0m") +print("\033[91mDEVICES STORAGE EVEN IF INSTALLATION IS FAILED\033[0m") +print("\033[91mPLEASE STOP THE INSTALLER USING STOP BUTTON\033[0m") +print("\033[91mIN THONNY TO ABORT INSTALLER AND NOT INSTALL\033[0m") +print("\033[91mGAMEBERRY ON YOUR DEVICE I'M ALSO NOT RESPONSIBLE\033[0m") +print("\033[91mFOR ANY BRICKS OF YOUR DEVICES OR LOST DATA\033[0m") +print("\033[91mINSTALLER WILL CONTINUE IN 5 SECONDS\033[0m") +log("Waiting 5 seconds") +time.sleep(5) +log("Warning accepted!") +print("") +log("Config:") +print("Config:") +log("Wi-Fi SSID: "+WiFi_SSID) +print("WiFi SSID: "+WiFi_SSID) +log("INA219: "+ str(INA219)) +print("INA219: "+str(INA219)) +log("SD READER: "+str(SD_READER)) +print("SD READER: " + str(SD_READER)) +print("") +log("Connecting to Wi-Fi") +print("Connecting to the Wi-Fi...") +wlan = network.WLAN(network.STA_IF) +wlan.active(True) +wlan.connect(WiFi_SSID, WiFi_PASSWORD) +wifi_i = 0 +while wlan.isconnected() == False and wifi_i is not 30: + time.sleep(1) + wifi_i = wifi_i + 1 +if wlan.isconnected() == False: + log("Could not connect to the Wi-Fi") + log("Error: " + str(wlan.status())) + log("Micropython Wlan Statuses:") + log(""" + STAT_IDLE -- 0 + STAT_CONNECTING -- 1 + STAT_WRONG_PASSWORD -- -3 + STAT_NO_AP_FOUND -- -2 + STAT_CONNECT_FAIL -- -1 + STAT_GOT_IP -- 3 + """) + print("\033[91mWi-Fi connections timeout please check your password or signal strenght\033[0m") + log("Waiting 5 seconds") + time.sleep(5) + log("Reboting...") + machine.soft_reset() +print("Format flash...") +log("force_not_to_format_flash is "+str(force_not_to_format_flash)) +if force_not_to_format_flash == False: + log("Formatting flash...") + format_flash() +else: + log("Skipped formatting flash...") + print("\033[92mSkipped flash formatting, force_not_to_format_flash set to "+str(force_not_to_format_flash)+"\033[0m") + +log("Downloading download list...") +log("Download list URL: " + download_list_url) +print("Downloading download list..") +if download_list(download_list_url) == True: + log("Download successfull") + print("Downloading successfull") +else: + log("\033[91mDownload failed\033[0m") + print("Downloading failed") + log("Waiting 5 seconds") + time.sleep(5) + log("Rebooting...") + machine.soft_reset() +log("Showing version of download list (Line 2)") +print(readline(2, download_list_path)) + +log("Starting install...") +print("Starting install...") +log("Reading list...") +print("Read list...") +line = 1 +is_end = False +is_started = False +lines_before_start = 0 +max_line_before_start = 10 +while is_end == False: + log("Reading line "+ str(line)) + read = readline(line, download_list_path) + log("Line: "+str(read)) + if is_started == False: + if read == "START": + log("Download list started") + print("Download list started") + is_started = True + else: + lines_before_start = lines_before_start + 1 + log("Lines before start: "+str(lines_before_start)) + if lines_before_start == max_line_before_start: + log("Much lines before start probably a trap") + log("Lines before start: " + str(lines_before_start)) + log("Max lines before start: " + str(max_line_before_start)) + print("\033[91mToo much lines before start of the list probably a trap\033[0m") + print("Please stop the script if waiting more than 15 seconds for starting") + print("Then report as issue on Github") + if is_started == True: + if read == "create-device-config": + log("Creating device config...") + print("Writing device config...") + write_device_config(INA219, SD_READER) + elif read == "folder": + log("Creating folder...") + print("Creating folder...") + log("Reading folder name to be created...") + line = line + 1 + read = readline(line, download_list_path) + log("Creating folder: " + read) + os.mkdir("/" + read) + log("Created folder") + print("Created folder: " + read) + elif read == "download": + log("Downloading file...") + print("Downloading file...") + log("Reading target path...") + line = line + 1 + path = readline(line, download_list_path) + log("Target file path: "+path) + print("Path: /" + path) + log("Reading file download URL...") + line = line + 1 + url = readline(line, download_list_path) + log("File download URL: "+url) + print("URL: " + url) + log("Downloading file...") + download_file(url, "/" + path) + log("Downloaded") + print("Downloaded") + elif read == "message": + log("Got message from download list") + log("Reading content") + line = line + 1 + printer = readline(line, download_list_path) + log("Content: "+printer) + print(printer) + elif read == "time": + log("Got wait command") + log("Reading time to wait...") + line = line + 1 + time = readline(line, download_list_path) + log("Time to wait: "+str(time)) + log("Waiting...") + time.sleep(float(time)) + elif read == "log-message": + line = line + 1 + printer = readline(line, download_list_path) + log("[DL] " + printer) + elif read == "comment": + # Ignore command + line = line + 1 + elif read == "write": + log("Writing to file") + line = line + 1 + name = readline(line, download_list_path) + log("Path: "+name) + line = line + 1 + content = readline(line, download_list_path) + log("Content: "+content) + with open(name, "w") as file: + file.write(content) + elif read == "write-append": + log("Writing to file") + line = line + 1 + name = readline(line, download_list_path) + log("Path: "+name) + line = line + 1 + content = readline(line, download_list_path) + log("Content: "+content) + with open(name, "a") as file: + file.write(content) + elif read == "END": + print("End of list") + is_end = True + else: + print("Unknown command: "+read) + print("Aborting installer") + machine.soft_reset() + line = line + 1 +os.remove(download_list_path) +print("\033[92mInstalation successfull\033[0m") +print("Rebooting...") +machine.soft_reset() + +# By Kitki30 \ No newline at end of file