Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 66 additions & 66 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ tasks:
- task app:build
- task app:zip
- |
ZIP_FILE=$(ls -t build/scratch-arduino-app-*.zip 2>/dev/null | head -n1)
if [ -z "$ZIP_FILE" ]; then
echo "No zip file found. Run 'task app:zip' first."
exit 1
fi
adb push "$ZIP_FILE" /tmp/
ZIP_BASENAME=$(basename "$ZIP_FILE")
adb shell "cd /tmp && unzip -o $ZIP_BASENAME && mkdir -p /home/arduino/ArduinoApps && rm -rf /home/arduino/ArduinoApps/scratch-arduino-app && mv scratch-arduino-app /home/arduino/ArduinoApps/ && rm $ZIP_BASENAME"
echo "App deployed to /home/arduino/ArduinoApps/scratch-arduino-app"
ZIP_FILE=$(ls -t build/scratch-arduino-app-*.zip 2>/dev/null | head -n1)
if [ -z "$ZIP_FILE" ]; then
echo "No zip file found. Run 'task app:zip' first."
exit 1
fi
adb push "$ZIP_FILE" /tmp/
ZIP_BASENAME=$(basename "$ZIP_FILE")
adb shell "cd /tmp && unzip -o $ZIP_BASENAME && mkdir -p /home/arduino/ArduinoApps && rm -rf /home/arduino/ArduinoApps/scratch-arduino-app && mv scratch-arduino-app /home/arduino/ArduinoApps/ && rm $ZIP_BASENAME"
echo "App deployed to /home/arduino/ArduinoApps/scratch-arduino-app"
- task app:start

app:build:
Expand All @@ -65,10 +65,10 @@ tasks:
sh: echo "${APP_VERSION:-$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')}"
cmds:
- |
if [ ! -d "build/scratch-arduino-app" ]; then
echo "Build folder does not exist. Run 'task app:build' first."
exit 1
fi
if [ ! -d "build/scratch-arduino-app" ]; then
echo "Build folder does not exist. Run 'task app:build' first."
exit 1
fi
- echo "Creating zip with version {{.APP_VERSION}}"
- cd build && zip -r scratch-arduino-app-{{.APP_VERSION}}.zip scratch-arduino-app && cd ..

Expand All @@ -91,69 +91,69 @@ tasks:
silent: true
cmds:
- |
while true; do
echo "🐍 Waiting for changes in python folder..."
inotifywait -r -e modify,create,delete,move python/ 2>/dev/null || {
echo "inotifywait failed, retrying..."
sleep 2
continue
}

sleep 1 # Waiting 1 second for file writes to complete..."
echo "🐍 Change detected: uploading and restarting service..."
task python:upload-and-restart || {
echo "Upload/restart failed, continuing to watch..."
continue
}

done
while true; do
echo "🐍 Waiting for changes in python folder..."
inotifywait -r -e modify,create,delete,move python/ 2>/dev/null || {
echo "inotifywait failed, retrying..."
sleep 2
continue
}

sleep 1 # Waiting 1 second for file writes to complete..."
echo "🐍 Change detected: uploading and restarting service..."
task python:upload-and-restart || {
echo "Upload/restart failed, continuing to watch..."
continue
}

done

python:upload-and-restart:
desc: "Upload Python files and restart container"
silent: true
cmds:
- |
adb push ./python/ /home/arduino/ArduinoApps/scratch-arduino-app/
adb push ./python/ /home/arduino/ArduinoApps/scratch-arduino-app/

CONTAINER_ID=$(adb shell "docker ps -q --filter 'ancestor=ghcr.io/arduino/app-bricks/python-apps-base:0.5.0'")
if [ -n "$CONTAINER_ID" ]; then
/usr/bin/time -f "🐍 Restarted in %es" adb shell "docker restart $CONTAINER_ID"
else
echo "[warning] No running container found with image ghcr.io/arduino/app-bricks/python-apps-base"
fi
CONTAINER_ID=$(adb shell "docker ps -q --filter 'ancestor=ghcr.io/arduino/app-bricks/python-apps-base:0.5.0'")
if [ -n "$CONTAINER_ID" ]; then
/usr/bin/time -f "🐍 Restarted in %es" adb shell "docker restart $CONTAINER_ID"
else
echo "[warning] No running container found with image ghcr.io/arduino/app-bricks/python-apps-base"
fi

sketch:watch:
desc: "Watch sketch folder for changes and auto-compile/upload"
silent: true
cmds:
- |
while true; do
echo "♾️ Waiting for changes in sketch folder..."
inotifywait -r -e modify,create,delete sketch/ --include '\.(ino|cpp|h|c)$' 2>/dev/null || {
echo "inotifywait failed, retrying..."
sleep 2
continue
}

sleep 1 # Waiting 1 second for file writes to complete
echo "♾️ Change detected: compiling and uploading..."
task sketch:compile-and-upload|| {
echo "Compile/upload failed, continuing to watch..."
continue
}
echo
done
while true; do
echo "♾️ Waiting for changes in sketch folder..."
inotifywait -r -e modify,create,delete sketch/ --include '\.(ino|cpp|h|c|yaml)$' 2>/dev/null || {
echo "inotifywait failed, retrying..."
sleep 2
continue
}

sleep 1 # Waiting 1 second for file writes to complete
echo "♾️ Change detected: compiling and uploading..."
task sketch:compile-and-upload|| {
echo "Compile/upload failed, continuing to watch..."
continue
}
echo
done

sketch:compile-and-upload:
desc: "Compile and upload Arduino sketch"
silent: true
cmds:
- |
TOTAL_START=$(date +%s)
/usr/bin/time -f "♾️ Compiled in %es" arduino-cli compile --build-path .cache -b arduino:zephyr:unoq sketch/
/usr/bin/time -f "♾️ Uploaded in %es" arduino-cli upload -p /dev/ttyACM0 -b arduino:zephyr:unoq:flash_mode=ram --input-dir .cache sketch/
TOTAL_END=$(date +%s)
echo "♾️ Total time: $((TOTAL_END - TOTAL_START))s"
TOTAL_START=$(date +%s)
/usr/bin/time -f "♾️ Compiled in %es" arduino-cli compile --build-path .cache -b arduino:zephyr:unoq sketch/
/usr/bin/time -f "♾️ Uploaded in %es" arduino-cli upload -p /dev/ttyACM0 -b arduino:zephyr:unoq:flash_mode=ram --input-dir .cache sketch/
TOTAL_END=$(date +%s)
echo "♾️ Total time: $((TOTAL_END - TOTAL_START))s"
# even if not necessary: the sketch folder is sync into the board to have the updated version
- adb push ./sketch/ /home/arduino/ArduinoApps/scratch-arduino-app/

Expand All @@ -168,12 +168,12 @@ tasks:
desc: "Watch sketch folder for changes and auto-compile/upload"
cmds:
- |
echo "🐍 Python container logs"
while true; do
CONTAINER_ID=$(adb shell "docker ps -q --filter 'ancestor=ghcr.io/arduino/app-bricks/python-apps-base:0.5.0'")
if [ -n "$CONTAINER_ID" ]; then
adb shell "docker logs -f $CONTAINER_ID"
else
echo "[warning] No running container found with image ghcr.io/arduino/app-bricks/python-apps-base"
fi
done
echo "🐍 Python container logs"
while true; do
CONTAINER_ID=$(adb shell "docker ps -q --filter 'ancestor=ghcr.io/arduino/app-bricks/python-apps-base:0.5.0'")
if [ -n "$CONTAINER_ID" ]; then
adb shell "docker logs -f $CONTAINER_ID"
else
echo "[warning] No running container found with image ghcr.io/arduino/app-bricks/python-apps-base"
fi
done
163 changes: 87 additions & 76 deletions scratch-prg-extensions/extensions/src/arduino_basics/index.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,111 @@
import { type Environment, extension, type ExtensionMenuDisplayDetails, scratch } from "$common";
import {
type Environment,
extension,
type ExtensionMenuDisplayDetails,
scratch,
} from "$common";
import { io, Socket } from "socket.io-client";
import MatrixArgument from "./MatrixArgument.svelte";

const details: ExtensionMenuDisplayDetails = {
name: "Basic",
description: "Play with UNO Q matrix, leds and pins",
iconURL: "matrix.png",
insetIconURL: "unoq.svg",
tags: ["Arduino UNO Q"],
blockColor: "#00878F",
menuColor: "#8C7965",
menuSelectColor: "#62AEB2",
name: "Basic",
description: "Play with UNO Q matrix, leds and pins",
iconURL: "matrix.png",
insetIconURL: "unoq.svg",
tags: ["Arduino UNO Q"],
blockColor: "#00878F",
menuColor: "#8C7965",
menuSelectColor: "#62AEB2",
};

// Get Arduino board IP or hostname from URL parameter
const getArduinoBoardHost = () => {
const urlParams = new URLSearchParams(window.location.search);
const boardHost = urlParams.get("host");
if (boardHost) {
return boardHost;
}
return window.location.hostname;
const urlParams = new URLSearchParams(window.location.search);
const boardHost = urlParams.get("host");
if (boardHost) {
return boardHost;
}
return window.location.hostname;
};

// TODO: make the block to support the brightness `0-7' of the leds
const PATTERNS = {
heart: [
[0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0],
[0, 0, 7, 0, 0, 7, 0, 7, 0, 0, 7, 0, 0],
[0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, 0],
[0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0],
[0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0],
[0, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0],
[0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0],
] as number[][],
arduino: [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 7, 7, 7, 0, 0, 0, 7, 7, 7, 0, 0],
[0, 7, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0],
[7, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7],
[7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7],
[7, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7],
[0, 7, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0],
[0, 0, 7, 7, 7, 0, 0, 0, 7, 7, 7, 0, 0],
] as number[][],
empty: Array(8).fill(null).map(() => Array(13).fill(0)) as number[][],
heart: [
[0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0],
[0, 0, 7, 0, 0, 7, 0, 7, 0, 0, 7, 0, 0],
[0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, 0],
[0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0],
[0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0],
[0, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0],
[0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0],
] as number[][],
arduino: [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 7, 7, 7, 0, 0, 0, 7, 7, 7, 0, 0],
[0, 7, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0],
[7, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7],
[7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7],
[7, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7],
[0, 7, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0],
[0, 0, 7, 7, 7, 0, 0, 0, 7, 7, 7, 0, 0],
] as number[][],
empty: Array(8)
.fill(null)
.map(() => Array(13).fill(0)) as number[][],
} as const;

export default class ArduinoBasics extends extension(details, "ui", "customArguments") {
private socket: Socket | null = null;
export default class ArduinoBasics extends extension(
details,
"ui",
"customArguments",
) {
private socket: Socket | null = null;

init(env: Environment) {
const arduinoBoardHost = getArduinoBoardHost();
var serverURL = `wss://${arduinoBoardHost}:7000`;
init(env: Environment) {
const arduinoBoardHost = getArduinoBoardHost();
var serverURL = `wss://${arduinoBoardHost}:7000`;

console.log("Connecting to Uno Q", serverURL);
console.log("Connecting to Uno Q", serverURL);

this.socket = io(serverURL, {
path: "/socket.io",
transports: ["polling", "websocket"],
autoConnect: true,
});
this.socket = io(serverURL, {
path: "/socket.io",
transports: ["polling", "websocket"],
autoConnect: true,
});

this.socket.on("connect", () => {
console.log(`Connected to Arduino UNO Q`);
});
this.socket.on("connect", () => {
console.log(`Connected to Arduino UNO Q`);
});

this.socket.on("disconnect", (reason) => {
console.log(`Disconnected from Arduino UNO Q: ${reason}`);
});
}
this.socket.on("disconnect", (reason) => {
console.log(`Disconnected from Arduino UNO Q: ${reason}`);
});
}

@scratch.command(function(_, tag) {
const arg = this.makeCustomArgument({
component: MatrixArgument,
initial: {
value: PATTERNS.arduino,
text: "arduino",
},
});
return tag`draw ${arg} matrix`;
})
drawMatrix(matrix: number[][]) {
var matrixString = matrix.flat().join("");
console.log("received matrix update", matrixString);
if (this.socket) {
this.socket.emit("matrix_draw", { frame: matrixString });
@scratch.command(function (_, tag) {
const arg = this.makeCustomArgument({
component: MatrixArgument,
initial: {
value: PATTERNS.arduino,
text: "arduino",
},
});
return tag`draw ${arg} matrix`;
})
drawMatrix(matrix: number[][]) {
var matrixString = matrix.flat().join("");
console.log("received matrix update", matrixString);
if (this.socket) {
this.socket.emit("matrix_draw", { frame: matrixString });
}
}
}

@scratch.command`Clear matrix`
clearMatrix(matrix: number[][]) {
var matrixString = PATTERNS.empty.flat().join("");
if (this.socket) {
this.socket.emit("matrix_draw", { frame: matrixString });
@(scratch.command`Clear matrix`)
clearMatrix() {
var matrixString = PATTERNS.empty.flat().join("");
if (this.socket) {
this.socket.emit("matrix_draw", { frame: matrixString });
}
}
}
}
8 changes: 8 additions & 0 deletions sketch/sketch.ino
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <Arduino_RouterBridge.h>
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
#include <Arduino_Modulino.h>

Expand All @@ -7,6 +8,9 @@ ModulinoButtons buttons;

void setup() {
matrix.begin();
matrix.textFont(Font_5x7);
matrix.textScrollSpeed(100);

Bridge.begin();
Modulino.begin(Wire1);
// show led indication if buttons cannot be initilized
Expand Down Expand Up @@ -48,6 +52,10 @@ void loop() {
uint8_t shades[104];

void matrix_draw(String frame){
matrix.beginText(0, 0, 127, 0, 0); // X, Y, then R, G, B
matrix.print(" arduino.cc/uno-q ");
matrix.endText(SCROLL_LEFT);

if (frame.length() != 104) {
Serial.println("Error: Frame length must be 104 characters.");
return;
Expand Down
1 change: 1 addition & 0 deletions sketch/sketch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ profiles:
- STM32duino VL53L4ED (1.0.1)
- Arduino_LSM6DSOX (1.1.2)
- Arduino_LPS22HB (1.0.2)
- ArduinoGraphics (1.1.4)
default_profile: default
Loading