diff --git a/package.json b/package.json index 3327c984..729b2f32 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "remark-gfm": "^3.0.1", "styled-components": "^4.4.1", "uuid": "^8.3.1", - "watchpack": "^2.3.1" + "watchpack": "^2.3.1", + "zustand": "3" }, "resolutions": { "//": "See https://github.com/facebook/create-react-app/issues/11773", diff --git a/public/media/blockly/blueLed.png b/public/media/blockly/blueLed.png new file mode 100644 index 00000000..1df44b78 Binary files /dev/null and b/public/media/blockly/blueLed.png differ diff --git a/public/media/blockly/offLed.png b/public/media/blockly/offLed.png new file mode 100644 index 00000000..05430203 Binary files /dev/null and b/public/media/blockly/offLed.png differ diff --git a/public/media/blockly/redLed.png b/public/media/blockly/redLed.png new file mode 100644 index 00000000..424c214d Binary files /dev/null and b/public/media/blockly/redLed.png differ diff --git a/public/media/blockly/yellowLed.png b/public/media/blockly/yellowLed.png new file mode 100644 index 00000000..c0d692dd Binary files /dev/null and b/public/media/blockly/yellowLed.png differ diff --git a/src/App.css b/src/App.css index cc1e993c..827ad253 100644 --- a/src/App.css +++ b/src/App.css @@ -1,3 +1,8 @@ +.blocklyLabelBig { + font-size: 10.5em; + font-weight: bold; +} + .wrapper { min-height: calc( 100vh - 60px diff --git a/src/App.jsx b/src/App.jsx index 57c96268..cb00b937 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,7 +7,6 @@ import { Provider } from "react-redux"; import store from "./store"; import { loadUser } from "./actions/authActions"; import ErrorBoundary from "./components/ErrorBoundary"; - import "./App.css"; import { @@ -18,6 +17,7 @@ import { import Content from "./components/Content"; import { setCompiler } from "./actions/generalActions"; +import { useLevelStore } from "./store/useLevelStore"; const theme = createTheme({ palette: { @@ -47,6 +47,16 @@ class App extends Component { // set initial compiler console.log("compiler", import.meta.env.VITE_INITIAL_COMPILER_URL); store.dispatch(setCompiler(import.meta.env.VITE_INITIAL_COMPILER_URL)); + + const params = new URLSearchParams(window.location.search); + const lvl = params.get("level"); + if (lvl !== null) { + const n = parseInt(lvl, 10); + if (!isNaN(n) && [1, 2, 3, 4].includes(n)) { + // setLevel im Zustand-Store aufrufen + useLevelStore.getState().setLevel(n); + } + } } render() { diff --git a/src/components/Blockly/BlocklyComponent.jsx b/src/components/Blockly/BlocklyComponent.jsx index 5412bddb..4fd1734c 100644 --- a/src/components/Blockly/BlocklyComponent.jsx +++ b/src/components/Blockly/BlocklyComponent.jsx @@ -16,8 +16,11 @@ import { } from "@blockly/plugin-scroll-options"; import { PositionedMinimap } from "@blockly/workspace-minimap"; +import LevelSelector from "./LevelSelector"; +import { useLevelStore } from "../../store/useLevelStore"; class BlocklyComponent extends React.Component { + level = 0; constructor(props) { super(props); this.blocklyDiv = React.createRef(); diff --git a/src/components/Blockly/LevelSelector.tsx b/src/components/Blockly/LevelSelector.tsx new file mode 100644 index 00000000..2e07d4d0 --- /dev/null +++ b/src/components/Blockly/LevelSelector.tsx @@ -0,0 +1,110 @@ +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Button, IconButton } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { useLevelStore } from "../../store/useLevelStore"; +import MenuItem from "@mui/material/MenuItem"; +import Menu from "@mui/material/Menu"; +import { faCaretDown, faLevelUp } from "@fortawesome/free-solid-svg-icons"; + +interface LevelSelectorProps {} + +const LevelSelector: React.FC = ({}) => { + const selectedLevel = useLevelStore((state) => state.level); + const setLevel = useLevelStore((state) => state.setLevel); + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleSelect = (level: number) => { + setLevel(level); + handleClose(); + }; + + useEffect(() => { + console.log("Selected level changed:", selectedLevel); + }, [selectedLevel]); + + const handleClose = () => { + setAnchorEl(null); + }; + + return ( +
+ + + handleSelect(1)}> + + Level 1 + + handleSelect(2)}> + + Level 2 + + handleSelect(3)}> + + Level 3 + + handleSelect(4)}> + + Level 4 + + {" "} + {/* {[1, 2, 3].map((level) => ( + handleSelect(level)} + style={{ + padding: "8px 16px", + background: selectedLevel === level ? "#1976d2" : "#e0e0e0", + color: selectedLevel === level ? "#fff" : "#000", + border: "none", + borderRadius: "4px", + cursor: "pointer", + fontWeight: selectedLevel === level ? "bold" : "normal", + }} + > + {level} + + ))} */} +
+ ); +}; + +export default LevelSelector; diff --git a/src/components/Blockly/blocks/sensebox-display.js b/src/components/Blockly/blocks/sensebox-display.js index 47bb123a..7f279f95 100644 --- a/src/components/Blockly/blocks/sensebox-display.js +++ b/src/components/Blockly/blocks/sensebox-display.js @@ -88,6 +88,25 @@ Blockly.Blocks["sensebox_display_printDisplay"] = { LOOP_TYPES: ["sensebox_display_show"], }; +Blockly.Blocks["sensebox_display_printEasy"] = { + init: function (block) { + this.setColour(getColour().sensebox); + this.appendDummyInput().appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/833/833313.png", + 30, + 30, + ), + ); + + this.appendValueInput("printDisplay").setCheck(null); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tooltip); + this.setHelpUrl(Blockly.Msg.senseBox_display_helpurl); + }, +}; + Blockly.Blocks["sensebox_display_fastPrint"] = { init: function (block) { this.setColour(getColour().sensebox); diff --git a/src/components/Blockly/blocks/sensebox-led.js b/src/components/Blockly/blocks/sensebox-led.js index 505db953..0ccea896 100644 --- a/src/components/Blockly/blocks/sensebox-led.js +++ b/src/components/Blockly/blocks/sensebox-led.js @@ -107,13 +107,64 @@ Blockly.Blocks["sensebox_ws2818_led"] = { this.setTooltip(Blockly.Msg.senseBox_ws2818_rgb_led_tooltip); if (selectedBoard().title === "MCU-S2") { this.setHelpUrl(Blockly.Msg.senseBox_ws2818_rgb_led_helpurl); - } - else { + } else { this.setHelpUrl(Blockly.Msg.senseBox_ws2818_rgb_led_helpurl_2); } }, }; +Blockly.Blocks["sensebox_ws2818_led_red"] = { + init: function () { + this.setColour(getColour().sensebox); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + + this.appendDummyInput().appendField( + new Blockly.FieldImage("./media/blockly/redLed.png", 30, 30, "*"), + "IMAGE", + ); + }, +}; + +Blockly.Blocks["sensebox_ws2818_led_yellow"] = { + init: function () { + this.setColour(getColour().sensebox); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + + this.appendDummyInput().appendField( + new Blockly.FieldImage("./media/blockly/yellowLed.png", 30, 30, "*"), + "IMAGE", + ); + }, +}; + +Blockly.Blocks["sensebox_ws2818_led_blue"] = { + init: function () { + this.setColour(getColour().sensebox); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + + this.appendDummyInput().appendField( + new Blockly.FieldImage("./media/blockly/blueLed.png", 30, 30, "*"), + "IMAGE", + ); + }, +}; + +Blockly.Blocks["sensebox_ws2818_led_off"] = { + init: function () { + this.setColour(getColour().sensebox); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + + this.appendDummyInput().appendField( + new Blockly.FieldImage("./media/blockly/offLed.png", 30, 30, "*"), + "IMAGE", + ); + }, +}; + Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT // Block for colour picker. @@ -262,8 +313,6 @@ Blockly.Blocks["sensebox_ws2812_matrix_text"] = { this.setNextStatement(true, null); this.setTooltip(Blockly.Msg.senseBox_ws2812_rgb_matrix_print_tooltip); this.setHelpUrl(Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl); - - }, }; @@ -293,7 +342,6 @@ Blockly.Blocks["sensebox_ws2812_matrix_drawPixel"] = { this.setNextStatement(true, null); this.setTooltip(Blockly.Msg.senseBox_ws2812_rgb_matrix_draw_pixel_tooltip); this.setHelpUrl(Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl); - }, }; @@ -311,7 +359,6 @@ Blockly.Blocks["sensebox_ws2812_matrix_clear"] = { this.setNextStatement(true, null); this.setTooltip(Blockly.Msg.senseBox_ws2812_rgb_matrix_clear_tooltip); this.setHelpUrl(Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl); - }, }; @@ -332,7 +379,6 @@ Blockly.Blocks["sensebox_ws2812_matrix_showBitmap"] = { this.setNextStatement(true, null); this.setTooltip(Blockly.Msg.senseBox_ws2812_rgb_matrix_show_bitmap_tooltip); this.setHelpUrl(Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl); - }, }; @@ -358,7 +404,6 @@ Blockly.Blocks["sensebox_ws2812_matrix_bitmap"] = { this.setOutput(true, Types.BITMAP.typeName); this.setTooltip(Blockly.Msg.senseBox_ws2812_rgb_matrix_bitmap_tooltip); this.setHelpUrl(Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl); - }, }; @@ -902,7 +947,6 @@ Blockly.defineBlocksWithJsonArray([ colour: getColour().sensebox, tooltip: Blockly.Msg.senseBox_ws2812_rgb_matrix_draw_bitmap_tooltip, helpUrl: Blockly.Msg.senseBox_ws2812_rgb_matrix_helpurl, - }, ]); diff --git a/src/components/Blockly/blocks/sensebox-sensors.js b/src/components/Blockly/blocks/sensebox-sensors.js index 6a7e4bbb..174c1d8b 100644 --- a/src/components/Blockly/blocks/sensebox-sensors.js +++ b/src/components/Blockly/blocks/sensebox-sensors.js @@ -5,6 +5,7 @@ import { selectedBoard } from "../helpers/board"; import { FieldGridDropdown } from "@blockly/field-grid-dropdown"; import { FieldSlider } from "@blockly/field-slider"; import { withBoardParam } from "../helpers/helpUrlBuilder"; +import { useLevelStore } from "../../../store/useLevelStore"; /** * HDC1080 Temperature and Humidity Sensor @@ -13,17 +14,30 @@ import { withBoardParam } from "../helpers/helpUrlBuilder"; Blockly.Blocks["sensebox_sensor_temp_hum"] = { init: function () { - this.appendDummyInput().appendField(Blockly.Msg.senseBox_temp_hum); - this.appendDummyInput() - .setAlign(Blockly.inputs.Align.RIGHT) - .appendField(Blockly.Msg.senseBox_value) - .appendField( - new Blockly.FieldDropdown([ - [Blockly.Msg.senseBox_temp, "Temperature"], - [Blockly.Msg.senseBox_hum, "Humidity"], - ]), - "NAME", + let level = useLevelStore.getState().level; + if (level === 1) { + this.appendDummyInput().appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/4158/4158502.png", + 40, + 40, + "senseBox HDC1080", + ), ); + } else { + this.appendDummyInput().appendField(Blockly.Msg.senseBox_temp_hum); + this.appendDummyInput() + .setAlign(Blockly.inputs.Align.RIGHT) + .appendField(Blockly.Msg.senseBox_value) + .appendField( + new Blockly.FieldDropdown([ + [Blockly.Msg.senseBox_temp, "Temperature"], + [Blockly.Msg.senseBox_hum, "Humidity"], + ]), + "NAME", + ); + } + this.setOutput(true, Types.DECIMAL.typeName); this.setColour(getColour().sensebox); this.setTooltip(Blockly.Msg.senseBox_temp_hum_tooltip); @@ -39,17 +53,29 @@ Blockly.Blocks["sensebox_sensor_temp_hum"] = { Blockly.Blocks["sensebox_sensor_uv_light"] = { init: function () { - this.appendDummyInput().appendField(Blockly.Msg.senseBox_uv_light); - this.appendDummyInput() - .setAlign(Blockly.inputs.Align.RIGHT) - .appendField(Blockly.Msg.senseBox_value) - .appendField( - new Blockly.FieldDropdown([ - [Blockly.Msg.senseBox_light, "Illuminance"], - [Blockly.Msg.senseBox_uv, "UvIntensity"], - ]), - "NAME", + let level = useLevelStore.getState().level; + if (level === 1) { + this.appendDummyInput().appendField( + new Blockly.FieldImage( + "https://cdn3.iconfinder.com/data/icons/meteocons/512/sun-symbol-512.png", + 40, + 40, + "senseBox VEML6070", + ), ); + } else { + this.appendDummyInput().appendField(Blockly.Msg.senseBox_uv_light); + this.appendDummyInput() + .setAlign(Blockly.inputs.Align.RIGHT) + .appendField(Blockly.Msg.senseBox_value) + .appendField( + new Blockly.FieldDropdown([ + [Blockly.Msg.senseBox_light, "Illuminance"], + [Blockly.Msg.senseBox_uv, "UvIntensity"], + ]), + "NAME", + ); + } this.setOutput(true, Types.DECIMAL.typeName); this.setColour(getColour().sensebox); this.setTooltip(Blockly.Msg.senseBox_uv_light_tooltip); @@ -317,25 +343,38 @@ Blockly.Blocks["sensebox_sensor_ultrasonic_ranger"] = { Blockly.Blocks["sensebox_tof_imager"] = { init: function () { - var dropdownOptions = [ - [Blockly.Msg.sensebox_distance, "DistanzCM"], - [Blockly.Msg.sensebox_distance_bitmap, "DistanzBM"], - ]; - var dropdown = new Blockly.FieldDropdown(dropdownOptions); + let level = useLevelStore.getState().level; + if (level === 1) { + this.appendDummyInput().appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/1189/1189097.png", + 40, + 40, + "senseBox ToF Imager", + ), + ); + } else { + var dropdownOptions = [ + [Blockly.Msg.sensebox_distance, "DistanzCM"], + [Blockly.Msg.sensebox_distance_bitmap, "DistanzBM"], + ]; + var dropdown = new Blockly.FieldDropdown(dropdownOptions); + this.appendDummyInput().appendField(Blockly.Msg.sensebox_tof_imager); + this.appendDummyInput() + .setAlign(Blockly.inputs.Align.RIGHT) + .appendField(Blockly.Msg.senseBox_value) + .appendField(dropdown, "dropdown"); + this.getField("dropdown").setValidator( + function (val) { + this.updateShape_(val === "DistanzBM"); + }.bind(this), + ); + } this.setColour(getColour().sensebox); - this.appendDummyInput().appendField(Blockly.Msg.sensebox_tof_imager); - this.appendDummyInput() - .setAlign(Blockly.inputs.Align.RIGHT) - .appendField(Blockly.Msg.senseBox_value) - .appendField(dropdown, "dropdown"); + this.setOutput(true, Types.NUMBER.typeName); this.setTooltip(Blockly.Msg.sensebox_tof_imager_tooltip); this.setHelpUrl(withBoardParam(Blockly.Msg.sensebox_tof_imager_helpurl)); - this.getField("dropdown").setValidator( - function (val) { - this.updateShape_(val === "DistanzBM"); - }.bind(this), - ); }, updateShape_(isAltitude) { if (isAltitude) { diff --git a/src/components/Blockly/blocks/time.js b/src/components/Blockly/blocks/time.js index 65cb6a28..72b1260b 100644 --- a/src/components/Blockly/blocks/time.js +++ b/src/components/Blockly/blocks/time.js @@ -150,3 +150,81 @@ Blockly.Blocks["sensebox_interval_timer"] = { this.setNextStatement(true, null); }, }; + +Blockly.Blocks["time_delay_1s"] = { + /** + * Delay block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl("http://arduino.cc/en/Reference/Delay"); + this.setColour(getColour().time); + + // Erst das Icon, dann eine große "1" + this.appendDummyInput() + .appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/31/31048.png", + 30, + 30, + ), + ) + .appendField(new Blockly.FieldLabel("1", ""), "DELAY_TIME_1S"); + this.setPreviousStatement(true, null); + + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP); + }, +}; + +Blockly.Blocks["time_delay_2s"] = { + /** + * Delay block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl("http://arduino.cc/en/Reference/Delay"); + this.setColour(getColour().time); + + // Erst das Icon, dann eine große "1" + this.appendDummyInput() + .appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/31/31048.png", + 30, + 30, + ), + ) + .appendField(new Blockly.FieldLabel("2", ""), "DELAY_TIME_1S"); + + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP); + }, +}; + +Blockly.Blocks["time_delay_5s"] = { + /** + * Delay block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl("http://arduino.cc/en/Reference/Delay"); + this.setColour(getColour().time); + + // Erst das Icon, dann eine große "1" + this.appendDummyInput() + .appendField( + new Blockly.FieldImage( + "https://cdn-icons-png.flaticon.com/512/31/31048.png", + 30, + 30, + ), + ) + .appendField(new Blockly.FieldLabel("5", ""), "DELAY_TIME_1S"); + this.setPreviousStatement(true, null); + + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP); + }, +}; diff --git a/src/components/Blockly/generator/sensebox-display.js b/src/components/Blockly/generator/sensebox-display.js index 8cde9df6..c3b51d74 100644 --- a/src/components/Blockly/generator/sensebox-display.js +++ b/src/components/Blockly/generator/sensebox-display.js @@ -1,5 +1,44 @@ +import { Block } from "@mui/icons-material"; import * as Blockly from "blockly/core"; +/** + * Helfer: Initialisiert das OLED-Display (Adafruit SSD1306) nur einmal pro Sketch. + * + * @param {object} blockGenerator Referenz auf Blockly.Generator.Arduino + */ +function initDisplay(blockGenerator) { + // 1) Bibliotheken nur einmal hinzufügen + blockGenerator.libraries_["library_spi"] = "#include "; + blockGenerator.libraries_["library_wire"] = "#include "; + blockGenerator.libraries_["library_AdafruitGFX"] = + "#include // http://librarymanager/All#Adafruit_GFX_Library"; + blockGenerator.libraries_["library_AdafruitSSD1306"] = + "#include // http://librarymanager/All#Adafruit_SSD1306"; + + // 2) Definitions (Größe und Instanz) nur hinzufügen, wenn noch nicht vorhanden + const defSizeKey = "define_display_size"; + if (!blockGenerator.definitions_[defSizeKey]) { + blockGenerator.definitions_[defSizeKey] = + "#define SCREEN_WIDTH 128\n#define SCREEN_HEIGHT 64"; + } + + const defDisplayKey = "define_display"; + if (!blockGenerator.definitions_[defDisplayKey]) { + blockGenerator.definitions_[defDisplayKey] = + "#define OLED_RESET -1\nAdafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);"; + } + + // 3) Setup-Code (display.begin, display.display, clearDisplay) nur einmal einfügen + const setupKey = "sensebox_display_begin"; + if (!blockGenerator.setupCode_[setupKey]) { + blockGenerator.setupCode_[setupKey] = + "display.begin(SSD1306_SWITCHCAPVCC, 0x3D);\n" + + "display.display();\n" + + "delay(100);\n" + + "display.clearDisplay();\n"; + } +} + /*Display Blocks*/ Blockly.Generator.Arduino.forBlock["sensebox_display_beginDisplay"] = function () { @@ -45,6 +84,28 @@ Blockly.Generator.Arduino.forBlock["sensebox_display_printDisplay"] = return code; }; +Blockly.Generator.Arduino.forBlock["sensebox_display_printEasy"] = function () { + initDisplay(Blockly.Generator.Arduino); + var x = 0; + var y = 0; + var printDisplay = + Blockly.Generator.Arduino.valueToCode( + this, + "printDisplay", + Blockly.Generator.Arduino.ORDER_ATOMIC, + ) || '"Keine Eingabe"'; + var size = 2; + var color = "WHITE"; + + var code = "display.setCursor(" + x + "," + y + ");\n"; + code += "display.setTextSize(" + size + ");\n"; + code += "display.setTextColor(" + color + ");\n"; + code += "display.println(" + printDisplay + ");\n"; + code += "display.display();\n"; + + return code; +}; + Blockly.Generator.Arduino.forBlock["sensebox_display_fastPrint"] = function () { var title1 = Blockly.Generator.Arduino.valueToCode( @@ -220,24 +281,23 @@ Blockly.Generator.Arduino.forBlock["sensebox_display_plotDisplay"] = return code; }; - Blockly.Generator.Arduino.forBlock["sensebox_display_roboeyes"] = - function () { - Blockly.Generator.Arduino.definitions_["define_roboeyes"] = - "#include \n" + - "roboEyes roboEyes;\n"; - Blockly.Generator.Arduino.setupCode_["sensebox_roboeye_setup"] = +Blockly.Generator.Arduino.forBlock["sensebox_display_roboeyes"] = function () { + Blockly.Generator.Arduino.definitions_["define_roboeyes"] = + "#include \n" + "roboEyes roboEyes;\n"; + Blockly.Generator.Arduino.setupCode_["sensebox_roboeye_setup"] = "roboEyes.begin(SCREEN_WIDTH, SCREEN_HEIGHT, 100);\n"; - let code = ""; - var position = this.getFieldValue("POSITION") || "DEFAULT"; - code += "roboEyes.setPosition(" + position + ");\n"; - var emotion = this.getFieldValue("EMOTION") || "DEFAULT"; - code += "roboEyes.setMood(" + emotion + ");\n"; - code += "roboEyes.drawEyes();\n" + + let code = ""; + var position = this.getFieldValue("POSITION") || "DEFAULT"; + code += "roboEyes.setPosition(" + position + ");\n"; + var emotion = this.getFieldValue("EMOTION") || "DEFAULT"; + code += "roboEyes.setMood(" + emotion + ");\n"; + code += + "roboEyes.drawEyes();\n" + "roboEyes.drawEyes();\n" + "roboEyes.drawEyes();\n" + "roboEyes.drawEyes();\n"; - return code; - }; + return code; +}; Blockly.Generator.Arduino.forBlock["sensebox_display_fillCircle"] = function () { diff --git a/src/components/Blockly/generator/sensebox-led.js b/src/components/Blockly/generator/sensebox-led.js index 38665b4d..82a38ff9 100644 --- a/src/components/Blockly/generator/sensebox-led.js +++ b/src/components/Blockly/generator/sensebox-led.js @@ -85,6 +85,106 @@ Blockly.Generator.Arduino.forBlock["sensebox_ws2818_led"] = function () { return code; }; +/** + * Helfer: Initialisiert (falls noch nicht geschehen) eine NeoPixel-Instanz + * - pin: Der GPIO-Pin (z.B. "1") + * - numPixel: Anzahl der Pixel (hier immer 1) + * - brightness: Globale Helligkeit (z.B. 50) + */ +function initNeoPixel(blockGenerator, pin, numPixel, brightness) { + // Bibliothek nur einmal hinzufügen + blockGenerator.libraries_["library_neopixel"] = + "#include "; + + // Definition nur hinzufügen, wenn es für diesen Pin noch keine Definition gibt + const defKey = "define_rgb_led" + pin; + if (!blockGenerator.definitions_[defKey]) { + blockGenerator.definitions_[defKey] = + `Adafruit_NeoPixel rgb_led_${pin} = Adafruit_NeoPixel(${numPixel}, ${pin}, NEO_GRB + NEO_KHZ800);\n`; + } + + // setup.begin() nur einmal einfügen + const setupBeginKey = "setup_rgb_led" + pin; + if (!blockGenerator.setupCode_[setupBeginKey]) { + blockGenerator.setupCode_[setupBeginKey] = `rgb_led_${pin}.begin();\n`; + } + + // setup.setBrightness() nur einmal einfügen + const setupBrightKey = "setup_rgb_led_brightness" + pin; + if (!blockGenerator.setupCode_[setupBrightKey]) { + blockGenerator.setupCode_[setupBrightKey] = + `rgb_led_${pin}.setBrightness(${brightness});\n`; + } +} + +Blockly.Generator.Arduino.forBlock["sensebox_ws2818_led_red"] = function ( + block, +) { + const dropdown_pin = 1; + const position = 0; + const numPixel = 1; + const brightness = 50; + const color = "255, 0, 0"; // Rot + + initNeoPixel(Blockly.Generator.Arduino, dropdown_pin, numPixel, brightness); + + const code = + `rgb_led_${dropdown_pin}.setPixelColor(${position}, rgb_led_${dropdown_pin}.Color(${color}));\n` + + `rgb_led_${dropdown_pin}.show();\n`; + return code; +}; + +Blockly.Generator.Arduino.forBlock["sensebox_ws2818_led_blue"] = function ( + block, +) { + const dropdown_pin = 1; + const position = 0; + const numPixel = 1; + const brightness = 50; + const color = "0, 0, 255"; // Blau + + initNeoPixel(Blockly.Generator.Arduino, dropdown_pin, numPixel, brightness); + + const code = + `rgb_led_${dropdown_pin}.setPixelColor(${position}, rgb_led_${dropdown_pin}.Color(${color}));\n` + + `rgb_led_${dropdown_pin}.show();\n`; + return code; +}; + +Blockly.Generator.Arduino.forBlock["sensebox_ws2818_led_yellow"] = function ( + block, +) { + const dropdown_pin = 1; + const position = 0; + const numPixel = 1; + const brightness = 50; + const color = "255, 255,0 "; // Blau + + initNeoPixel(Blockly.Generator.Arduino, dropdown_pin, numPixel, brightness); + + const code = + `rgb_led_${dropdown_pin}.setPixelColor(${position}, rgb_led_${dropdown_pin}.Color(${color}));\n` + + `rgb_led_${dropdown_pin}.show();\n`; + return code; +}; + +Blockly.Generator.Arduino.forBlock["sensebox_ws2818_led_yellow"] = function ( + block, +) { + const dropdown_pin = 1; + const position = 0; + const numPixel = 1; + const brightness = 50; + const color = "255, 255,0 "; // Blau + + initNeoPixel(Blockly.Generator.Arduino, dropdown_pin, numPixel, brightness); + + const code = + `rgb_led_${dropdown_pin}.setPixelColor(${position}, rgb_led_${dropdown_pin}.Color(${color}));\n` + + `rgb_led_${dropdown_pin}.show();\n`; + return code; +}; + function hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result diff --git a/src/components/Blockly/generator/time.js b/src/components/Blockly/generator/time.js index d99f5fb7..6cdded8f 100644 --- a/src/components/Blockly/generator/time.js +++ b/src/components/Blockly/generator/time.js @@ -143,3 +143,30 @@ Blockly.Generator.Arduino.forBlock["sensebox_interval_timer"] = function ( `; return code; }; + +Blockly.Generator.Arduino.forBlock["time_delay_1s"] = function ( + block, + generator, +) { + var delayTime = 1000; + var code = "delay(" + delayTime + ");\n"; + return code; +}; + +Blockly.Generator.Arduino.forBlock["time_delay_2s"] = function ( + block, + generator, +) { + var delayTime = 2000; + var code = "delay(" + delayTime + ");\n"; + return code; +}; + +Blockly.Generator.Arduino.forBlock["time_delay_5s"] = function ( + block, + generator, +) { + var delayTime = 5000; + var code = "delay(" + delayTime + ");\n"; + return code; +}; diff --git a/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel1.jsx b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel1.jsx new file mode 100644 index 00000000..406c483d --- /dev/null +++ b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel1.jsx @@ -0,0 +1,37 @@ +import { Block, Value, Field, Statement, Shadow, Category, Label } from "../.."; +import { getColour } from "../../helpers/colour"; +import * as Blockly from "blockly/core"; + +export const ToolBoxEspLevel1 = (props) => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel2.jsx b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel2.jsx new file mode 100644 index 00000000..ab629f12 --- /dev/null +++ b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel2.jsx @@ -0,0 +1,267 @@ +import { Block, Value, Field, Statement, Shadow, Category, Label } from "../.."; +import { getColour } from "../../helpers/colour"; +import * as Blockly from "blockly/core"; +export const ToolBoxEspLevel2 = (props) => { + return ( + <> + + + + + + + + + + + + + + + + + + 1 + + + + + + + 1 + + + + + + + + + 1 + + + + + 30 + + + + + + + 0 + + + + + 0 + + + + + + + + + 100 + + + + + 50 + + + + + 0 + + + + + + + + + + + + + + 1 + + + + + 0 + + + + + 0 + + + + + + + Title + + + + + Unit + + + + + Title + + + + + Unit + + + + + + + + + + + + + + + + 0 + + + + + 15 + + + + + 0 + + + + + 50 + + + + + 5 + + + + + 0 + + + + + 15 + + + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100 + + + + + 50 + + + + + 0 + + + + + + + + + + + + + + + + + ); +}; diff --git a/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel3.jsx b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel3.jsx new file mode 100644 index 00000000..94643968 --- /dev/null +++ b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel3.jsx @@ -0,0 +1,635 @@ +import { Block, Value, Field, Statement, Shadow, Category, Label } from "../.."; +import { getColour } from "../../helpers/colour"; +import * as Blockly from "blockly/core"; + +export const ToolBoxEspLevel3 = (props) => { + return ( + <> + + + + + + + + + + + + + + + + + + 1 + + + + + + + 1 + + + + + + + + + 1 + + + + + 30 + + + + + + + 0 + + + + + 0 + + + + + + + + + 100 + + + + + 50 + + + + + 0 + + + + + + + + + + + + + + 1 + + + + + 0 + + + + + 0 + + + + + + + Title + + + + + Unit + + + + + Title + + + + + Unit + + + + + + + + + + + + + + + + 0 + + + + + 15 + + + + + 0 + + + + + 50 + + + + + 5 + + + + + 0 + + + + + 15 + + + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 100 + + + + + 50 + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + latitude + + + + + longitude + + + + + altitude + + + + + pDOP + + + + + fixType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* + + */} + + + + + + + + + + + + + + + + 10 + + + + + + + + 1 + + + + + 10 + + + + + 1 + + + + + + + + + + + + + + + + + 1 + + + + + + + + + 1 + + + + + 100 + + + + + + + 1 + + + + + 100 + + + + + + + + + + + 220 + + + + + + + + + + + + 1000 + + + + + + + 100 + + + + + + + + + + + + + + + 00 + + + + + 00 + + + + + 00 + + + + + 01 + + + + + 01 + + + + + 1970 + + + + {/* */} + + + + + + + + + + ); +}; + +{ + /* + + battery_level + + + 30 + * 1000 + + + 30 + 60000 + TRUE + TRUE + TRUE + + + + + GT + + + battery_level + + + + + 2 + + + + + + + 30 + 60000 + TRUE + TRUE + TRUE + + + + + 12 + 3600000 + TRUE + TRUE + TRUE + + + + */ +} diff --git a/src/components/Blockly/toolbox/ToolboxEsp.jsx b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel4.jsx similarity index 97% rename from src/components/Blockly/toolbox/ToolboxEsp.jsx rename to src/components/Blockly/toolbox/ESP/ToolBoxEspLevel4.jsx index 538c6b94..dcce3aa1 100644 --- a/src/components/Blockly/toolbox/ToolboxEsp.jsx +++ b/src/components/Blockly/toolbox/ESP/ToolBoxEspLevel4.jsx @@ -1,30 +1,19 @@ -import { Block, Value, Field, Statement, Shadow, Category, Label } from ".."; -import { getColour } from "../helpers/colour"; +import { Block, Value, Field, Statement, Shadow, Category, Label } from "../.."; +import { getColour } from "../../helpers/colour"; import * as Blockly from "blockly/core"; -import "@blockly/toolbox-search"; -import "./search-category.css"; -export const ToolboxEsp = () => { +export const ToolBoxEspLevel4 = (props) => { return ( <> - - {" "} - - + - - - - - - - + @@ -48,45 +37,6 @@ export const ToolboxEsp = () => { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -134,36 +84,6 @@ export const ToolboxEsp = () => { - - - - - - - - - - - - - - - - 100 - - - - - 50 - - - - - 0 - - - - @@ -294,6 +214,86 @@ export const ToolboxEsp = () => { + + + + + + + + + + + + + + + + + + + + + + + + 100 + + + + + 50 + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -401,57 +401,6 @@ export const ToolboxEsp = () => { */} - {/* - - battery_level - - - 30 - * 1000 - - - 30 - 60000 - TRUE - TRUE - TRUE - - - - - GT - - - battery_level - - - - - 2 - - - - - - - 30 - 60000 - TRUE - TRUE - TRUE - - - - - 12 - 3600000 - TRUE - TRUE - TRUE - - - - */} @@ -512,98 +461,6 @@ export const ToolboxEsp = () => { - - - - - - - - - - - - - - - - - 1000 - - - - - - - 100 - - - - - - - - - - - - - - - 00 - - - - - 00 - - - - - 00 - - - - - 01 - - - - - 01 - - - - - 1970 - - - - {/* */} - - - - - - - - { + + + + + + 1000 + + + + + + + 100 + + + + + + + + + + + + + + + 00 + + + + + 00 + + + + + 00 + + + + + 01 + + + + + 01 + + + + + 1970 + + + + {/* */} + + + + + + + + ); }; + +{ + /* + + battery_level + + + 30 + * 1000 + + + 30 + 60000 + TRUE + TRUE + TRUE + + + + + GT + + + battery_level + + + + + 2 + + + + + + + 30 + 60000 + TRUE + TRUE + TRUE + + + + + 12 + 3600000 + TRUE + TRUE + TRUE + + + + */ +} diff --git a/src/components/Blockly/toolbox/ESP/ToolboxEsp.jsx b/src/components/Blockly/toolbox/ESP/ToolboxEsp.jsx new file mode 100644 index 00000000..b9ff2862 --- /dev/null +++ b/src/components/Blockly/toolbox/ESP/ToolboxEsp.jsx @@ -0,0 +1,25 @@ +import { Block, Value, Field, Statement, Shadow, Category, Label } from "../.."; +import { getColour } from "../../helpers/colour"; +import * as Blockly from "blockly/core"; +import "@blockly/toolbox-search"; +import "../search-category.css"; +import { useLevelStore } from "../../../../store/useLevelStore"; +import { ToolBoxEspLevel1 } from "./ToolBoxEspLevel1"; +import { ToolBoxEspLevel2 } from "./ToolBoxEspLevel2"; +import { ToolBoxEspLevel3 } from "./ToolBoxEspLevel3"; +import { ToolBoxEspLevel4 } from "./ToolBoxEspLevel4"; + +export const ToolboxEsp = () => { + const level = useLevelStore((state) => state.level); + return ( + <> + + {" "} + + {level == 1 && } + {level == 2 && } + {level == 3 && } + {level == 4 && } + + ); +}; diff --git a/src/components/Blockly/toolbox/Toolbox.jsx b/src/components/Blockly/toolbox/Toolbox.jsx index 1c55a439..638a9d2c 100644 --- a/src/components/Blockly/toolbox/Toolbox.jsx +++ b/src/components/Blockly/toolbox/Toolbox.jsx @@ -4,9 +4,21 @@ import { TypedVariableModal } from "@blockly/plugin-typed-variable-modal"; import * as Blockly from "blockly/core"; import { connect } from "react-redux"; import { ToolboxMcu } from "./ToolboxMcu"; -import { ToolboxEsp } from "./ToolboxEsp"; +import { ToolboxEsp } from "./ESP/ToolboxEsp"; +import { useLevelStore } from "../../../store/useLevelStore"; class Toolbox extends React.Component { + selectedLevel = 0; + constructor(props) { + super(props); + this.state = { level: 0 }; + } + componentDidMount() { + this.level = useLevelStore.subscribe((newLevel) => { + // use set state to trigger component re-render + this.setState({ level: newLevel }); + }); + } componentDidUpdate(props) { this.props.workspace.registerToolboxCategoryCallback( "CREATE_TYPED_VARIABLE", @@ -32,7 +44,10 @@ class Toolbox extends React.Component { console.log(this.props.selectedBoard); this.setState({ board: this.props.selectedBoard }); } + this.props.workspace.updateToolbox(this.props.toolbox.current); + // close the flyout to update the toolbox' contents also + this.props.workspace.toolbox.flyout.setVisible(false); } createFlyout(workspace) { diff --git a/src/components/Home.jsx b/src/components/Home.jsx index dd7afd46..b2bd331e 100644 --- a/src/components/Home.jsx +++ b/src/components/Home.jsx @@ -23,6 +23,7 @@ import { faCode } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import TooltipViewer from "./TooltipViewer"; import Dialog from "./Dialog"; +import { useLevelStore } from "../store/useLevelStore"; // import Autosave from "./Workspace/AutoSave"; const styles = (theme) => ({ codeOn: { @@ -46,20 +47,30 @@ const styles = (theme) => ({ }); class Home extends Component { + level = 0; constructor(props) { super(props); this.state = { - codeOn: true, + codeOn: useLevelStore.getState().level === 4, snackbar: false, type: "", key: "", message: "", open: true, initialXml: localStorage.getItem("autoSaveXML"), + level: 1, }; } componentDidMount() { + this.level = useLevelStore.subscribe((newLevel) => { + if (newLevel.level == 4) { + this.setState({ codeOn: true }); + } else { + this.setState({ codeOn: false }); + } + }); + if (this.props.platform === true) { this.setState({ codeOn: false }); } diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index 886fee10..8faf0fc8 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -51,6 +51,7 @@ import Menu from "@mui/material/Menu"; import { setLanguage } from "../actions/generalActions"; import { setBoard } from "../actions/boardAction"; import { Button } from "@mui/material"; +import LevelSelector from "./Blockly/LevelSelector"; const styles = (theme) => ({ drawerWidth: { @@ -78,6 +79,7 @@ class Navbar extends Component { anchorElLang: null, anchorElBoard: null, anchorElUser: null, + anchorElLevel: null, }; } @@ -167,6 +169,8 @@ class Navbar extends Component { > {isHome ? (
+ +