Compare commits

...
Author SHA1 Message Date
DelucseandGitHub 1e95d57139 Update README.md 2020-11-19 17:52:23 +01:00
Delucse 104d432278 block labeling in german 2020-10-28 13:57:38 +01:00
Delucse 345aa57b7e consideration of higher-level parent node 2020-10-28 12:21:13 +01:00
Delucse f95beb9623 correcting loop tutorial tasks 2020-10-19 08:43:40 +02:00
Delucse 5999daa332 dialog - hint tutorials exists 2020-10-17 11:09:25 +02:00
Delucse a0fd63a2ca fix vertical stepper bug 2020-10-17 09:47:03 +02:00
Mario PeschandGitHub b310d290cf Merge pull request #18 from sensebox/fix/boolean-return-type
Fix/boolean return type
2020-10-16 15:01:06 +02:00
Mario 3f7ba6fbac fix checks 2020-10-16 14:51:39 +02:00
Mario 1950344862 fix return type 2020-10-16 14:46:34 +02:00
Mario PeschandGitHub 40d4c67be8 Merge pull request #16 from sensebox/resize-hardware-images
resize hardware images
2020-10-13 10:44:35 +02:00
Mario a809946899 resize hardware images 2020-10-13 10:35:31 +02:00
Mario PeschandGitHub e1f3bbdf03 Merge pull request #12 from sensebox/new-tutorial-structure
New tutorial structure
2020-10-13 10:06:32 +02:00
Mario PeschandGitHub b53a5b277c Merge pull request #14 from sensebox/block/co2-sensor
add co2 sensor
2020-10-13 10:03:38 +02:00
Mario 9f16e07c59 add co2 sensor 2020-10-12 15:06:33 +02:00
Mario PeschandGitHub 15ff312d48 Merge pull request #13 from sensebox/add-license-1
Create LICENSE
2020-10-08 18:05:51 +00:00
Mario PeschandGitHub 8b475cd0d8 Create LICENSE 2020-10-08 20:05:38 +02:00
Mario 08ee8b3b5c add display tutorial 2020-10-08 16:25:37 +02:00
Mario 83c8a4f296 change tile color in builder 2020-10-08 15:33:30 +02:00
Mario f660814897 resolve warnings 2020-10-08 15:31:33 +02:00
Mario 89d0cc380b update tutorial structure 2020-10-08 15:29:28 +02:00
Mario aaeaf7a5aa update logic and text blocks 2020-10-08 15:28:26 +02:00
Mario f709b4b757 update breadboard image 2020-10-08 15:28:07 +02:00
Mario 2a2c1e1c25 update loop blocks 2020-10-07 09:47:24 +02:00
Mario 40d8301990 update loops tutorial 2020-10-06 11:35:58 +02:00
Mario PeschandGitHub c99ca92a4e Merge pull request #10 from sensebox/use-viewport-height
use viewport height for blocklywindow
2020-10-05 07:21:44 +00:00
Delucse fc785b8b8d ensure that fill-opacity is 1 (blockly-svg) 2020-10-02 16:01:11 +02:00
Mario 14455547a4 use viewport height for blocklywindow 2020-10-02 14:55:16 +02:00
Mario PeschandGitHub 182b5ada77 Merge pull request #9 from sensebox/add-button-block
add block for the button
2020-10-02 12:33:37 +00:00
Mario 4fc0f14aed add block for the button 2020-10-02 14:30:24 +02:00
Delucse 5daa336a04 setting the maximum display size of the embedded youtube video 2020-09-30 16:58:02 +02:00
Delucse 1cd00dab3f Merge branch 'tutorial' 2020-09-30 15:59:22 +02:00
Delucse 9da57c5067 embed youtube video 2020-09-30 15:58:49 +02:00
Delucse f97ab10a53 Merge branch 'tutorial-builder' into tutorial 2020-09-30 15:41:52 +02:00
Delucse 56820a04fc possibility to add media (picture or youtube-video) to the instructions 2020-09-30 15:41:24 +02:00
Delucse 1cef36e0f2 embed picture 2020-09-30 09:41:31 +02:00
Delucse f7a0e7594d ensure that the correct xml-file is displayed in the workspace 2020-09-30 09:20:29 +02:00
Delucse 8991e2b40b possibility to add pictures to the instructions 2020-09-29 20:12:33 +02:00
Mario PeschandGitHub 67cc477d28 Merge pull request #7 from sensebox/typed-variables
Typed variables
2020-09-29 12:21:58 +00:00
Mario 44d14687be update code generation 2020-09-29 11:33:06 +02:00
Mario eceaa91713 Merge branch 'master' into typed-variables 2020-09-29 11:28:57 +02:00
Mario d64512ed9e add math types 2020-09-29 11:25:07 +02:00
Mario 5304907fd0 add block type to setter and getter 2020-09-29 10:30:35 +02:00
Mario da4c8840ea update blockly version 2020-09-29 10:30:13 +02:00
Delucse 3a92a6a08c fix error status in tutorial-builder 2020-09-28 15:54:39 +02:00
Delucse 8d752e0430 precondition for each tutorial is at least one instruction and one task 2020-09-28 15:41:17 +02:00
Delucse 4a5d24f2d1 template created for not deactivated blocks in the instructions 2020-09-28 15:12:19 +02:00
Delucse 8ec8409504 Update WorkspaceFunc.js 2020-09-27 20:57:56 +02:00
Delucse 078d53e7e2 Merge branch 'tutorial' 2020-09-27 20:36:07 +02:00
Delucse 7ca3b466ea create screenshot of workspace 2020-09-27 20:35:03 +02:00
Delucse 9d99c5c30b display of the blocks as SVG in instruction-component 2020-09-27 20:15:11 +02:00
Delucse 9b2d66aee7 fix bug in local storage logic 2020-09-25 13:40:42 +02:00
Delucse 1d3f356fe7 fix warning "no-loop-func" 2020-09-25 13:22:09 +02:00
Delucse 5044b09701 updated links to get more specific information about hardware 2020-09-25 12:51:37 +02:00
DelucseandGitHub 994f74d7ad Update README.md 2020-09-22 14:19:26 +02:00
Delucse b1038c447b create redirect file to get access to links based on react-router-dom 2020-09-22 12:44:45 +02:00
Delucse 3f4e559866 Merge branch 'tutorial-builder' 2020-09-22 11:57:02 +02:00
Delucse 2a7b9dd4d7 Merge branch 'snackbar' 2020-09-22 11:56:56 +02:00
Delucse 59d347de41 fix warnings in tutorial builder 2020-09-22 11:56:36 +02:00
Delucse 6cfcd97647 key prop to ensure independent treatment 2020-09-22 11:35:29 +02:00
Delucse 6a21410709 hide snackbar after 5 seconds 2020-09-22 11:34:03 +02:00
Delucse 9e9c523955 Merge branch 'snackbar' 2020-09-21 12:16:57 +02:00
Delucse 9df7de05f4 adjustment of colours and messages in case of error 2020-09-21 12:16:10 +02:00
Delucse 0f0bfb98c6 add snackbar to tutorial builder 2020-09-21 11:41:19 +02:00
Delucse 9574462fbf add snackbar to workspace functions 2020-09-21 11:41:01 +02:00
Delucse ece3514cb3 initialize snackbar 2020-09-21 11:40:33 +02:00
Delucse 0029f7cc26 another way to initialize an array to fix bug 2020-09-20 16:45:24 +02:00
Delucse 420477e02c breadcrumbs adjustment 2020-09-20 16:31:14 +02:00
Delucse 1518787e13 Merge branch 'tutorial-builder' 2020-09-20 16:29:03 +02:00
Delucse a46ca93763 navlink tutorial-builder 2020-09-20 16:26:37 +02:00
Delucse 660abe9712 reorganize data files like tutorials.json 2020-09-20 16:23:18 +02:00
Delucse e20a40aaf5 definig specific error in step component 2020-09-20 16:22:07 +02:00
Delucse b03ef6b54a completing the metadata in hardware.json 2020-09-20 14:58:27 +02:00
Delucse 15a83f56fc fix bug in blockly example 2020-09-20 14:15:18 +02:00
Delucse 812c01d6bc layout tutorial builder 2020-09-20 13:59:42 +02:00
Delucse fc1b898c80 upload JSON string 2020-09-20 13:48:19 +02:00
Delucse 3ba35751ea fix bugs concerning uploading json 2020-09-20 00:09:05 +02:00
Delucse 7579be52c9 upload JSON file 2020-09-19 23:21:43 +02:00
Delucse 28ced177bd generate JSON-file 2020-09-19 09:57:16 +02:00
Delucse 111b924988 error validation 2020-09-19 09:38:38 +02:00
felixerdy 3e3f0be41f typed variables working partially 2020-09-18 16:21:49 +02:00
Delucse b20bde4e83 tutorial builder 2020-09-18 16:21:27 +02:00
Delucse 253424037c step builder 2020-09-18 16:21:17 +02:00
Delucse 6d7f0fe609 blockly example creator 2020-09-18 16:21:00 +02:00
Delucse 07042ae055 hardware of steps 2020-09-18 16:20:10 +02:00
Delucse b78b704755 requirements of step 2020-09-18 16:20:00 +02:00
Delucse 45ac72a16e type of step 2020-09-18 16:19:50 +02:00
Delucse da29619694 textfield input 2020-09-18 16:19:36 +02:00
Delucse 458770e0c4 redux store of builder 2020-09-18 16:19:18 +02:00
felixerdy 136b85e027 initial implementation of typed variables 2020-09-18 15:19:58 +02:00
Delucse 1c2b025493 add id and title 2020-09-17 18:55:51 +02:00
Mario PeschandGitHub 38b025e012 Merge branch 'master' into new-blocks 2020-09-17 13:25:43 +00:00
Mario 42299a374a minor changes 2020-09-17 15:16:41 +02:00
Delucse d70207ea1a breadcrumbs with inital home-link 2020-09-17 14:13:30 +02:00
Delucse b726f5f42c Merge branch 'blockly-functions' 2020-09-17 13:24:38 +02:00
Delucse bde430dd40 detect whitespaces and return readable filename 2020-09-17 13:24:00 +02:00
Delucse 8bed9f4b7f Merge branch 'blockly-functions' 2020-09-17 12:57:07 +02:00
Delucse c85c96468c name of tutorial workspace is automatically derived from the tutorial title and the step heading 2020-09-17 12:56:43 +02:00
Delucse 5c43ff4648 name of the workspace and display of its 2020-09-17 11:55:46 +02:00
Delucse ba84bc512c set filename to save compiled blocks 2020-09-17 10:06:29 +02:00
Mario 6a4de9c7a2 fix warnings 2020-09-16 15:50:55 +02:00
Delucse 3c9404c5be deactivate redux devtools extension 2020-09-16 15:18:28 +02:00
Mario bbd14c58b5 add new blocks 2020-09-16 14:59:09 +02:00
Delucse 3d146155d0 Merge branch 'instruction' 2020-09-16 11:16:06 +02:00
Delucse 73c721f237 improved colour contrasts concerning tutorial status 2020-09-16 11:15:55 +02:00
Delucse 71e881283d improved feedback in terms of incorrect block count and success 2020-09-16 11:05:20 +02:00
Delucse 68af341816 cogs symbol to illustrate compiling 2020-09-16 10:49:56 +02:00
Delucse 11c3198c82 set filename to save blocks as xml-file 2020-09-16 10:42:18 +02:00
Delucse d3159d5204 Merge branch 'blockly-functions' into instruction 2020-09-15 18:50:26 +02:00
Delucse f7f95bbf9f solution check tooltip arrow 2020-09-15 18:50:12 +02:00
Delucse 7f3ad89623 Merge branch 'blockly-functions' into instruction 2020-09-15 18:44:37 +02:00
Delucse 20ac45a48d Merge branch 'assessment' into instruction 2020-09-15 18:44:23 +02:00
Delucse 02040bb656 Merge branch 'blockly-window' into instruction 2020-09-15 18:43:21 +02:00
Delucse 5cfb3c18de code-window is always visible for an assessment 2020-09-15 18:42:04 +02:00
Delucse 427467eb8a add workspace functions to assessment 2020-09-15 17:21:02 +02:00
Delucse 1c29dd2109 display statistics as menu, if screen is too small 2020-09-15 17:05:22 +02:00
Delucse 28fb2c3bab Merge branch 'instruction' into blockly-functions 2020-09-15 15:31:20 +02:00
Delucse 25134d4d86 hardware images without distortion 2020-09-15 15:29:59 +02:00
Delucse 4550977471 upload, download, compile and reset blocks 2020-09-15 14:39:47 +02:00
Delucse 567f94135b reorganize media files 2020-09-15 10:29:53 +02:00
Delucse 8060927cc6 adjustment of the hardware images so that the full image is visible 2020-09-15 10:21:50 +02:00
Mario 4df5b64eb0 add basic hardware images 2020-09-14 19:24:55 +02:00
Delucse 0f582e6d7d Merge branch 'instruction' 2020-09-14 19:00:57 +02:00
Delucse 84d4166cab display requirements 2020-09-14 19:00:15 +02:00
Mario PeschandGitHub edbf60d92e Merge pull request #5 from sensebox/add-slider
add led block
2020-09-14 14:24:51 +00:00
Mario 97ef7ab1bb update led pins 2020-09-14 15:58:22 +02:00
Mario 9a764b7e74 add led block 2020-09-14 15:41:57 +02:00
Delucse 93e047f4bf xs-display showing only two hardware-pictures 2020-09-14 13:33:21 +02:00
Delucse 9724d01b76 Merge branch 'master' into instruction 2020-09-14 13:26:29 +02:00
Delucse 823bb042ff showing needed hardware 2020-09-14 13:24:29 +02:00
Delucse 01c662b00f Merge remote-tracking branch 'origin/add-slider' 2020-09-13 16:04:06 +02:00
Delucse 7300cade5d each task (step) has its own id within a tutorial 2020-09-13 16:02:47 +02:00
Delucse 6f77b460cb add/ delete tutorials/steps in initial state of redux based on tutorials.json 2020-09-13 15:18:11 +02:00
Delucse f997bb661f update initialXml 2020-09-13 13:19:09 +02:00
Delucse e7723487c9 next step button or tutorial-overview button after solving task 2020-09-11 17:47:05 +02:00
Delucse f19842ccae status of tutorial and belonging tasks 2020-09-11 17:31:06 +02:00
Delucse 825075d656 next and back step - buttons 2020-09-11 11:00:57 +02:00
Delucse 6c3709fde8 adjustment of the tutorial component and all dependencies to the new tutorial.json 2020-09-11 10:13:33 +02:00
Delucse 33445cf67c tutorial.json 2020-09-11 09:08:31 +02:00
Delucse ab016610bd checking the Blocks with the solution using the XML strings 2020-09-10 13:46:31 +02:00
Delucse f14508a5ca own blocklyWindow for an instruction 2020-09-09 13:36:41 +02:00
Delucse 2908bc464f generalised BlocklyWindow 2020-09-09 13:35:35 +02:00
Mario 78f8bad4b3 add slider 2020-09-09 11:54:30 +02:00
Delucse 4f34811a94 store only xml if tutorial-id exists 2020-09-08 15:06:26 +02:00
Delucse eea893a071 stored xml in tutorial redux store 2020-09-08 14:43:30 +02:00
Delucse 7e0fbf1f75 current tutorial id stored in redux store 2020-09-08 13:42:55 +02:00
Delucse c1d3962fb4 Merge branch 'assessment' into tutorial 2020-09-08 12:07:55 +02:00
Delucse 29d77d0bc6 Revert "Revert "CodeViewer with referenced height of parent div""
This reverts commit 3297d01e78.
2020-09-08 12:03:49 +02:00
Delucse e766b05dba Merge branch 'tutorial' into assessment 2020-09-08 11:56:09 +02:00
Delucse de0bfd5d49 fixed status update of tutorials 2020-09-08 11:55:08 +02:00
Delucse 3297d01e78 Revert "CodeViewer with referenced height of parent div"
This reverts commit dddd9432db.
2020-09-08 11:30:34 +02:00
Delucse 6a94ce618c Revert "Merge branch 'assessment' into tutorial"
This reverts commit e322795f25, reversing
changes made to dddd9432db.
2020-09-08 11:30:25 +02:00
Delucse e322795f25 Merge branch 'assessment' into tutorial 2020-09-07 17:17:14 +02:00
Delucse dddd9432db CodeViewer with referenced height of parent div 2020-09-07 17:16:59 +02:00
Delucse 4c66ab9173 displaying the status of the tutorial 2020-09-07 15:57:09 +02:00
Delucse b42e466304 merge 2020-09-04 15:33:57 +02:00
Delucse c11ff8fc6c show vertical stepper not on extrasmall displays 2020-09-04 15:26:59 +02:00
Delucse 0e18c0bd23 elimination of password-bug 2020-09-04 15:15:22 +02:00
Delucse 1586e74cdc checked if wifi is initialized 2020-09-04 15:06:55 +02:00
Delucse c00c0949e4 clear workspace after changing tutorial 2020-09-04 11:50:04 +02:00
Delucse 7148d66d19 vertical tutorial stepper 2020-09-03 15:22:14 +02:00
Delucse ccf901d20b error page requesting a tutorial that does not (longer) exist 2020-09-02 11:43:17 +02:00
Delucse bcc4c35c9e improvement of tutorial stepper via material-ui 2020-09-01 13:23:56 +02:00
Delucse 5443932bf6 tutorial stepper 2020-08-31 17:26:58 +02:00
Delucse 8c13a9e316 splitting a tutorial into introduction and assessment 2020-08-31 16:52:30 +02:00
Delucse d379489a91 breadcrumbs 2020-08-31 13:53:39 +02:00
Delucse ab95f9eee6 overview of tutorials 2020-08-31 13:15:50 +02:00
Delucse f38a33fd4a URL dependent labeling of the toolbar 2020-08-31 12:35:33 +02:00
Delucse baa047f8d7 "code-on", "close trashcan", "delete trashcan" buttons 2020-08-10 14:30:08 +02:00
Delucse fdde372ef3 reset Workspace with initial XML-Block 2020-08-10 11:54:36 +02:00
Delucse 08dab82d00 showing CircularProgress while compiling 2020-08-10 10:06:34 +02:00
DelucseandGitHub c009674c46 Merge pull request #2 from sensebox/add-new-blocks
Add new blocks
2020-08-10 09:06:50 +02:00
Mario PeschandGitHub 30d8c0158e Merge pull request #4 from sensebox/compile
Compile
2020-08-04 13:14:48 +02:00
felixerdy ddd3fa1fcf online compiling 2020-08-03 16:38:18 +02:00
felixerdy fd4afa9e60 cleanup 2020-08-03 15:48:33 +02:00
Mario 6e56054d1d remove typography warning 2020-07-31 16:42:41 +02:00
Mario PeschandGitHub 736f3411df Merge pull request #3 from sensebox/styling
some styling
2020-07-31 16:37:30 +02:00
Mario dd874a2384 add LoRa Blocks 2020-07-31 16:37:09 +02:00
Mario 6678afbdff add map block 2020-07-31 16:18:45 +02:00
felixerdy 25aae52da3 some styling 2020-07-31 16:15:41 +02:00
Mario ef80f15782 add display and web blocks 2020-07-31 12:31:47 +02:00
Mario 0d70f66935 remove devtools 2020-07-31 12:31:34 +02:00
Mario b808474913 add language key 2020-07-31 11:36:02 +02:00
Mario 4e2b25947d solve compiling warnings 2020-07-31 11:27:53 +02:00
Mario 440622a66c add sensebox sensor blocks 2020-07-31 11:10:22 +02:00
Mario 44f2f3ca94 Merge branch 'master' into add-new-blocks 2020-07-26 12:15:57 +02:00
Delucse bd28c388be styling: cahnging color to 'white" 2020-07-24 19:49:40 +02:00
Delucse 9f33b93fdd recalculating positions of trash, zoom, etc 2020-07-24 19:15:41 +02:00
Delucse 338bec2d59 accordion to view code of different languages 2020-07-24 18:18:47 +02:00
Delucse b4a273b32a pretty code as output 2020-07-24 15:45:30 +02:00
Delucse 393c89877e code on/off 2020-07-24 12:24:14 +02:00
Delucse cacde16ab2 outsourcing BlocklyComponent to blockly/BlocklyWindow.js 2020-07-24 11:52:49 +02:00
Delucse a505fa7ad8 add grid 2020-07-24 11:07:20 +02:00
Delucse 7de0ffdebd trashcan, zoom-control and media 2020-07-24 11:02:07 +02:00
Mario eca3bf16a1 add io blocks 2020-07-23 16:04:00 +02:00
Delucse 168c5fb575 removing workspace from Redux 2020-07-23 15:55:54 +02:00
Delucse c2405de04a adaptation of the functionalities to Blockly package 2020-07-23 15:42:01 +02:00
DelucseandGitHub d1d7a447bc Merge pull request #1 from sensebox/add-arduino-generator
add arduino code generator
2020-07-23 12:05:54 +02:00
163 changed files with 22330 additions and 491 deletions
+2
View File
@@ -0,0 +1,2 @@
REACT_APP_COMPILER_URL=https://compiler.sensebox.de
REACT_APP_BOARD=sensebox-mcu
+1
View File
@@ -22,3 +22,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
package-lock.json
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="a119841b-a70a-4b0e-91b6-4da6cd81f169" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/src/components/Tutorial/tutorials.json" beforeDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="a119841b-a70a-4b0e-91b6-4da6cd81f169" name="Default Changelist" comment="" />
<created>1599559503505</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1599559503505</updated>
</task>
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
</project>
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+18 -58
View File
@@ -1,68 +1,28 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
<img src="/src/components/sensebox_logo.svg?raw=true" height="128" alt="senseBox Logo"/>
## Available Scripts
# React Ardublockly
In the project directory, you can run:
This repository contains the source code and documentation of [sensebox-ardublockly](https://sensebox-ardublockly.netlify.app/) :rocket:.
### `npm start`
This project was created with [Create React App](https://github.com/facebook/create-react-app) and represents the continuation or improvement of [blockly.sensebox.de](https://blockly.sensebox.de/ardublockly/?lang=de&board=sensebox-mcu).
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
## Getting Started
### `npm test`
1. [Download](https://github.com/sensebox/React-Ardublockly/archive/bachelor.zip) or clone the GitHub Repository ``git clone https://github.com/sensebox/React-Ardublockly`` and checkout to branch ``bachelor``.
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
2. install [Node.js v10.xx](https://nodejs.org/en/) on your local machine
### `npm run build`
3. open shell and navigate inside folder ``React-Ardublockly`` or rather ``Quellcode``
* run ``npm install``
* run ``npm start``
4. open [localhost:3000](http://localhost:3000)
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
## Troubleshoot
Ensure that line 14 in [store.js](https://github.com/sensebox/React-Ardublockly/blob/master/src/store.js#L14) is commented out or otherwise you have installed [Redux DevTools Extension](http://extension.remotedev.io/).
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `npm run build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
## Demo
A demo of the current status of the bachelor branch can be accessed via [sensebox-ardublockly.netlify.app](https://sensebox-ardublockly.netlify.app/) :rocket:.
* [Home](https://sensebox-ardublockly.netlify.app/)
* [Tutorial Overview](https://sensebox-ardublockly.netlify.app/tutorial)
* [Tutorial-Builder](https://sensebox-ardublockly.netlify.app/tutorial/builder)
+82 -3
View File
@@ -1096,6 +1096,29 @@
"to-fast-properties": "^2.0.0"
}
},
"@blockly/block-plus-minus": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@blockly/block-plus-minus/-/block-plus-minus-2.0.10.tgz",
"integrity": "sha512-YWEQd9xHAAn1aJgIuZsAdx2t9ZSjinaSEzbN1c43iU584TvaiPsGq5JcnLpoDIyGgJI90Nk+o4erWyQR+kqLyQ=="
},
"@blockly/field-slider": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@blockly/field-slider/-/field-slider-2.1.1.tgz",
"integrity": "sha512-VclXqKRs94iHl7yhFNCK+a1uyiHtPHgoAYXugr7hbZ6BZWGdI9tV1iMeiILz4pNlhy6llM+QvbJopjYA+4oCFQ=="
},
"@blockly/plugin-modal": {
"version": "1.20200427.4",
"resolved": "https://registry.npmjs.org/@blockly/plugin-modal/-/plugin-modal-1.20200427.4.tgz",
"integrity": "sha512-eA9p+W3mtcWLJQZ23D0Le/Uw3JdxFxwJqTUYtAiRlVON4qnuDXrHQLlvxEiWctNXJZGUTh57zqbvO6ZxNRQPrA=="
},
"@blockly/plugin-typed-variable-modal": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@blockly/plugin-typed-variable-modal/-/plugin-typed-variable-modal-3.1.1.tgz",
"integrity": "sha512-+g/lQ3HrCcivBNOtgvQEvfZCPq9VeP1Zgs7J02zxAfw4f+s4aOQb+hChv7qAb5AnzEnMk0BoB5vKgQmaP6Wkuw==",
"requires": {
"@blockly/plugin-modal": "^1.20200427.4"
}
},
"@cnakazawa/watch": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
@@ -3055,9 +3078,9 @@
}
},
"blockly": {
"version": "3.20200625.2",
"resolved": "https://registry.npmjs.org/blockly/-/blockly-3.20200625.2.tgz",
"integrity": "sha512-+0aUynP4kAFjg+m9uSyctWB+KwT3/BDmqy4Fm7vwWq7cuMtgIsqqA8VGb6INVpFx9WZUXSZ5enFAco6CM85bpA==",
"version": "3.20200924.0",
"resolved": "https://registry.npmjs.org/blockly/-/blockly-3.20200924.0.tgz",
"integrity": "sha512-mOZiXi908oNFAcVb8Q5LKJNRZ5jtBJtgNilddqTYMAXEdqSY/BhcnU2rgytWARDnu2iSQlI374kEafCNuUEWKQ==",
"requires": {
"jsdom": "^15.2.1"
},
@@ -3694,6 +3717,17 @@
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="
},
"clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"optional": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -4588,6 +4622,12 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"optional": true
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -5920,6 +5960,11 @@
"schema-utils": "^2.5.0"
}
},
"file-saver": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz",
"integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw=="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -6350,6 +6395,15 @@
}
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"optional": true,
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
@@ -8666,6 +8720,11 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.29.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
"integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -10490,6 +10549,14 @@
}
}
},
"prismjs": {
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz",
"integrity": "sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw==",
"requires": {
"clipboard": "^2.0.0"
}
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@@ -11659,6 +11726,12 @@
"ajv-keywords": "^3.4.1"
}
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"optional": true
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -12827,6 +12900,12 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"tiny-invariant": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
+7 -1
View File
@@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@blockly/block-plus-minus": "^2.0.10",
"@blockly/field-slider": "^2.1.1",
"@blockly/plugin-typed-variable-modal": "^3.1.1",
"@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11",
@@ -10,7 +13,10 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"blockly": "^3.20200625.2",
"blockly": "^3.20200924.0",
"file-saver": "^2.0.2",
"moment": "^2.28.0",
"prismjs": "^1.20.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
+1
View File
@@ -0,0 +1 @@
/* /index.html 200
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+3 -7
View File
@@ -2,13 +2,9 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta name="theme-color" content="#4EAF47" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
@@ -24,7 +20,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>senseBox Blockly</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
+4 -4
View File
@@ -3,9 +3,9 @@
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"type": "image/png"
},
{
"src": "logo192.png",
@@ -20,6 +20,6 @@
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
"theme_color": "#4EAF47",
"background_color": "#4EAF47"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="12.71" height="8.79" viewBox="0 0 12.71 8.79"><title>dropdown-arrow</title><g opacity="0.1"><path d="M12.71,2.44A2.41,2.41,0,0,1,12,4.16L8.08,8.08a2.45,2.45,0,0,1-3.45,0L0.72,4.16A2.42,2.42,0,0,1,0,2.44,2.48,2.48,0,0,1,.71.71C1,0.47,1.43,0,6.36,0S11.75,0.46,12,.71A2.44,2.44,0,0,1,12.71,2.44Z" fill="#231f20"/></g><path d="M6.36,7.79a1.43,1.43,0,0,1-1-.42L1.42,3.45a1.44,1.44,0,0,1,0-2c0.56-.56,9.31-0.56,9.87,0a1.44,1.44,0,0,1,0,2L7.37,7.37A1.43,1.43,0,0,1,6.36,7.79Z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
<style type="text/css">
#background {
fill: none;
}
.arrows {
fill: #000;
stroke: none;
}
.selected>.arrows {
fill: #fff;
}
.checkmark {
fill: #000;
font-family: sans-serif;
font-size: 10pt;
text-anchor: middle;
}
.trash {
fill: #888;
}
.zoom {
fill: none;
stroke: #888;
stroke-width: 2;
stroke-linecap: round;
}
.zoom>.center {
fill: #888;
stroke-width: 0;
}
</style>
<rect id="background" width="96" height="124" x="0" y="0" />
<g>
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<g class="selected" transform="translate(0, 16)">
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<text class="checkmark" x="55.5" y="28">&#10003;</text>
<g class="trash">
<path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
<rect width="36" height="20" x="5" y="50" />
<rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
</g>
<g class="zoom">
<circle r="11.5" cx="16" cy="108" />
<circle r="4.3" cx="16" cy="108" class="center" />
<path d="m 28,108 h3" />
<path d="m 1,108 h3" />
<path d="m 16,120 v3" />
<path d="m 16,93 v3" />
</g>
<g class="zoom">
<circle r="15" cx="48" cy="108" />
<path d="m 48,101.6 v12.8" />
<path d="m 41.6,108 h12.8" />
</g>
<g class="zoom">
<circle r="15" cx="80" cy="108" />
<path d="m 73.6,108 h12.8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.4 KiB

+2 -2
View File
@@ -1,7 +1,7 @@
.wrapper {
min-height: 100vh; /* will cover the 100% of viewport */
min-height: calc(100vh - 60px); /* will cover the 100% of viewport - height of footer (padding-bottom) */
overflow: hidden;
display: block;
position: relative;
padding-bottom: 60px; /* height of your footer + 30px*/y
padding-bottom: 60px; /* height of your footer + 30px*/
}
+10 -3
View File
@@ -1,10 +1,13 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { createBrowserHistory } from "history";
import { Provider } from 'react-redux';
import store from './store';
import './App.css';
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import Navbar from './components/Navbar';
@@ -15,21 +18,25 @@ const theme = createMuiTheme({
palette: {
primary: {
main: '#4EAF47',
contrastText: '#ffffff'
},
secondary: {
main: '#DDDDDD'
}
}
});
const customHistory = createBrowserHistory();
function App() {
return (
<ThemeProvider theme={theme}>
<Provider store={store}>
<Router>
<Router history={customHistory}>
<div className="wrapper">
<Navbar />
<div style={{ margin: '0 22px' }}>
<Routes />
</div>
<Footer />
</div>
</Router>
+8
View File
@@ -0,0 +1,8 @@
import { VISIT } from './types';
export const visitPage = () => (dispatch) => {
dispatch({
type: VISIT
});
};
+61
View File
@@ -0,0 +1,61 @@
import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from './types';
import tutorials from '../data/tutorials';
export const tutorialChange = () => (dispatch) => {
dispatch({
type: TUTORIAL_CHANGE
});
};
export const tutorialCheck = (status, step) => (dispatch, getState) => {
var tutorialsStatus = getState().tutorial.status;
var id = getState().tutorial.currentId;
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus.id === id);
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task.id === step.id);
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
type: status
};
dispatch({
type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
payload: tutorialsStatus
});
dispatch(tutorialChange());
};
export const storeTutorialXml = (code) => (dispatch, getState) => {
var id = getState().tutorial.currentId;
if (id !== null) {
var activeStep = getState().tutorial.activeStep;
var steps = tutorials.filter(tutorial => tutorial.id === id)[0].steps;
if (steps[activeStep].type === 'task') {
var tutorialsStatus = getState().tutorial.status;
var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus.id === id);
var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task.id === steps[activeStep].id);
tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex] = {
...tutorialsStatus[tutorialsStatusIndex].tasks[tasksIndex],
xml: code
};
dispatch({
type: TUTORIAL_XML,
payload: tutorialsStatus
});
}
}
};
export const tutorialId = (id) => (dispatch) => {
dispatch({
type: TUTORIAL_ID,
payload: id
});
};
export const tutorialStep = (step) => (dispatch) => {
dispatch({
type: TUTORIAL_STEP,
payload: step
});
};
+305
View File
@@ -0,0 +1,305 @@
import { PROGRESS, JSON_STRING, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types';
import data from '../data/hardware.json';
export const changeTutorialBuilder = () => (dispatch) => {
dispatch({
type: BUILDER_CHANGE
});
};
export const jsonString = (json) => (dispatch) => {
dispatch({
type: JSON_STRING,
payload: json
});
};
export const tutorialTitle = (title) => (dispatch) => {
dispatch({
type: BUILDER_TITLE,
payload: title
});
dispatch(changeTutorialBuilder());
};
export const tutorialSteps = (steps) => (dispatch) => {
dispatch({
type: BUILDER_ADD_STEP,
payload: steps
});
dispatch(changeTutorialBuilder());
};
export const tutorialId = (id) => (dispatch) => {
dispatch({
type: BUILDER_ID,
payload: id
});
dispatch(changeTutorialBuilder());
};
export const addStep = (index) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = {
id: index + 1,
type: 'instruction',
headline: '',
text: ''
};
steps.splice(index, 0, step);
dispatch({
type: BUILDER_ADD_STEP,
payload: steps
});
dispatch(addErrorStep(index));
dispatch(changeTutorialBuilder());
};
export const addErrorStep = (index) => (dispatch, getState) => {
var error = getState().builder.error;
error.steps.splice(index, 0, {});
dispatch({
type: BUILDER_ERROR,
payload: error
});
};
export const removeStep = (index) => (dispatch, getState) => {
var steps = getState().builder.steps;
steps.splice(index, 1);
dispatch({
type: BUILDER_DELETE_STEP,
payload: steps
});
dispatch(removeErrorStep(index));
dispatch(changeTutorialBuilder());
};
export const removeErrorStep = (index) => (dispatch, getState) => {
var error = getState().builder.error;
error.steps.splice(index, 1);
dispatch({
type: BUILDER_ERROR,
payload: error
});
};
export const changeContent = (content, index, property1, property2) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[index];
if (property2) {
if (step[property1] && step[property1][property2]) {
step[property1][property2] = content;
} else {
step[property1] = { [property2]: content };
}
} else {
step[property1] = content;
}
dispatch({
type: BUILDER_CHANGE_STEP,
payload: steps
});
dispatch(changeTutorialBuilder());
};
export const deleteProperty = (index, property1, property2) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[index];
if (property2) {
if (step[property1] && step[property1][property2]) {
delete step[property1][property2];
}
} else {
delete step[property1];
}
dispatch({
type: BUILDER_DELETE_PROPERTY,
payload: steps
});
dispatch(changeTutorialBuilder());
};
export const changeStepIndex = (fromIndex, toIndex) => (dispatch, getState) => {
var steps = getState().builder.steps;
var step = steps[fromIndex];
steps.splice(fromIndex, 1);
steps.splice(toIndex, 0, step);
dispatch({
type: BUILDER_CHANGE_ORDER,
payload: steps
});
dispatch(changeErrorStepIndex(fromIndex, toIndex));
dispatch(changeTutorialBuilder());
};
export const changeErrorStepIndex = (fromIndex, toIndex) => (dispatch, getState) => {
var error = getState().builder.error;
var errorStep = error.steps[fromIndex];
error.steps.splice(fromIndex, 1);
error.steps.splice(toIndex, 0, errorStep);
dispatch({
type: BUILDER_ERROR,
payload: error
});
};
export const setError = (index, property) => (dispatch, getState) => {
var error = getState().builder.error;
if (index !== undefined) {
error.steps[index][property] = true;
}
else {
error[property] = true;
}
dispatch({
type: BUILDER_ERROR,
payload: error
});
dispatch(changeTutorialBuilder());
};
export const deleteError = (index, property) => (dispatch, getState) => {
var error = getState().builder.error;
if (index !== undefined) {
delete error.steps[index][property];
}
else {
delete error[property];
}
dispatch({
type: BUILDER_ERROR,
payload: error
});
dispatch(changeTutorialBuilder());
};
export const setSubmitError = () => (dispatch, getState) => {
var builder = getState().builder;
// if(builder.id === undefined || builder.id === ''){
// dispatch(setError(undefined, 'id'));
// }
if (builder.id === undefined || builder.title === '') {
dispatch(setError(undefined, 'title'));
}
var type = builder.steps.map((step, i) => {
// media and xml are directly checked for errors in their components and
// therefore do not have to be checked again
step.id = i + 1;
if (i === 0) {
if (step.requirements && step.requirements.length > 0) {
var requirements = step.requirements.filter(requirement => typeof (requirement) === 'number');
if (requirements.length < step.requirements.length) {
dispatch(changeContent(requirements, i, 'requirements'));
}
}
if (step.hardware === undefined || step.hardware.length < 1) {
dispatch(setError(i, 'hardware'));
}
else {
var hardwareIds = data.map(hardware => hardware.id);
var hardware = step.hardware.filter(hardware => hardwareIds.includes(hardware));
if (hardware.length < step.hardware.length) {
dispatch(changeContent(hardware, i, 'hardware'));
}
}
}
if (step.headline === undefined || step.headline === '') {
dispatch(setError(i, 'headline'));
}
if (step.text === undefined || step.text === '') {
dispatch(setError(i, 'text'));
}
return step.type;
});
if (!(type.filter(item => item === 'task').length > 0 && type.filter(item => item === 'instruction').length > 0)) {
dispatch(setError(undefined, 'type'));
}
};
export const checkError = () => (dispatch, getState) => {
dispatch(setSubmitError());
var error = getState().builder.error;
if (error.id || error.title || error.type) {
return true;
}
for (var i = 0; i < error.steps.length; i++) {
if (Object.keys(error.steps[i]).length > 0) {
return true
}
}
return false;
}
export const progress = (inProgress) => (dispatch) => {
dispatch({
type: PROGRESS,
payload: inProgress
})
};
export const resetTutorial = () => (dispatch, getState) => {
dispatch(jsonString(''));
dispatch(tutorialTitle(''));
dispatch(tutorialId(''));
var steps = [
{
id: 1,
type: 'instruction',
headline: '',
text: '',
hardware: [],
requirements: []
}
];
dispatch(tutorialSteps(steps));
dispatch({
type: BUILDER_ERROR,
payload: {
steps: [{}]
}
});
};
export const readJSON = (json) => (dispatch, getState) => {
dispatch(resetTutorial());
dispatch({
type: BUILDER_ERROR,
payload: {
steps: json.steps.map(() => { return {}; })
}
});
// accept only valid attributes
var steps = json.steps.map((step, i) => {
var object = {
id: step.id,
type: step.type,
headline: step.headline,
text: step.text
};
if (i === 0) {
object.hardware = step.hardware;
object.requirements = step.requirements;
}
if (step.xml) {
object.xml = step.xml;
}
if (step.media && step.type === 'instruction') {
object.media = {};
if (step.media.picture) {
object.media.picture = step.media.picture;
}
else if (step.media.youtube) {
object.media.youtube = step.media.youtube;
}
}
return object;
});
dispatch(tutorialTitle(json.title));
dispatch(tutorialId(json.id));
dispatch(tutorialSteps(steps));
dispatch(setSubmitError());
dispatch(progress(false));
};
+28 -1
View File
@@ -1,5 +1,32 @@
export const NEW_WORKSPACE = 'NEW_WORKSPACE';
export const NEW_CODE = 'NEW_CODE';
export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE';
export const CREATE_BLOCK = 'CREATE_BLOCK';
export const MOVE_BLOCK = 'MOVE_BLOCK';
export const CHANGE_BLOCK = 'CHANGE_BLOCK';
export const DELETE_BLOCK = 'DELETE_BLOCK';
export const CLEAR_STATS = 'CLEAR_STATS';
export const NAME = 'NAME';
export const TUTORIAL_SUCCESS = 'TUTORIAL_SUCCESS';
export const TUTORIAL_ERROR = 'TUTORIAL_ERROR';
export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE';
export const TUTORIAL_XML = 'TUTORIAL_XML';
export const TUTORIAL_ID = 'TUTORIAL_ID';
export const TUTORIAL_STEP = 'TUTORIAL_STEP';
export const JSON_STRING = 'JSON_STRING';
export const BUILDER_CHANGE = 'BUILDER_CHANGE';
export const BUILDER_TITLE = 'BUILDER_TITLE';
export const BUILDER_ID = 'BUILDER_ID';
export const BUILDER_ADD_STEP = 'BUILDER_ADD_STEP';
export const BUILDER_DELETE_STEP = 'BUILDER_DELETE_STEP';
export const BUILDER_CHANGE_STEP = 'BUILDER_CHANGE_STEP';
export const BUILDER_CHANGE_ORDER = 'BUILDER_CHANGE_ORDER';
export const BUILDER_DELETE_PROPERTY = 'BUILDER_DELETE_PROPERTY';
export const BUILDER_ERROR = 'BUILDER_ERROR';
export const PROGRESS = 'PROGRESS';
export const VISIT = 'VISIT';
+46 -18
View File
@@ -1,29 +1,56 @@
import { NEW_WORKSPACE, CREATE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from './types';
import { NEW_CODE, CHANGE_WORKSPACE, CREATE_BLOCK, MOVE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS, NAME } from './types';
import * as Blockly from 'blockly/core';
import { storeTutorialXml } from './tutorialActions';
export const workspaceChange = () => (dispatch) => {
dispatch({
type: CHANGE_WORKSPACE
});
};
export const onChangeCode = () => (dispatch, getState) => {
const workspace = Blockly.getMainWorkspace();
var code = getState().workspace.code;
code.arduino = Blockly.Arduino.workspaceToCode(workspace);
var xmlDom = Blockly.Xml.workspaceToDom(workspace);
code.xml = Blockly.Xml.domToPrettyText(xmlDom);
dispatch({
type: NEW_CODE,
payload: code
});
return code;
};
export const onChangeWorkspace = (event) => (dispatch, getState) => {
var oldWorkspace = getState().workspace.new; // stored 'new workspace' is from now on old
var newWorkspace = window.Ardublockly.workspace;
dispatch({
type: NEW_WORKSPACE,
payload: {new: newWorkspace, old: oldWorkspace}
});
dispatch(workspaceChange());
var code = dispatch(onChangeCode());
dispatch(storeTutorialXml(code.xml));
var stats = getState().workspace.stats;
if (event.type === window.Blockly.Events.CREATE){
if (event.type === Blockly.Events.BLOCK_CREATE) {
stats.create += event.ids.length;
dispatch({
type: CREATE_BLOCK,
payload: stats
});
}
else if (event.type === window.Blockly.Events.CHANGE){
else if (event.type === Blockly.Events.BLOCK_MOVE) {
stats.move += 1;
dispatch({
type: MOVE_BLOCK,
payload: stats
});
}
else if (event.type === Blockly.Events.BLOCK_CHANGE) {
stats.change += 1;
dispatch({
type: CHANGE_BLOCK,
payload: stats
});
}
else if (event.type === window.Blockly.Events.DELETE){
if(stats.create > 0){
else if (event.type === Blockly.Events.BLOCK_DELETE) {
if (stats.create > 0) {
stats.delete += event.ids.length;
dispatch({
type: DELETE_BLOCK,
@@ -35,9 +62,10 @@ export const onChangeWorkspace = (event) => (dispatch, getState) => {
export const clearStats = () => (dispatch) => {
var stats = {
create: 0,
create: -1, // initialXML is created automatically, Block is not part of the statistics
change: 0,
delete: 0
delete: 0,
move: -1 // initialXML is moved automatically, Block is not part of the statistics
};
dispatch({
type: CLEAR_STATS,
@@ -45,9 +73,9 @@ export const clearStats = () => (dispatch) => {
});
};
export const setWorkspace = (workspace) => (dispatch, getState) => {
export const workspaceName = (name) => (dispatch) => {
dispatch({
type: NEW_WORKSPACE,
payload: {new: workspace, old: getState().workspace.new}
});
};
type: NAME,
payload: name
})
}
@@ -1,6 +0,0 @@
#blocklyDiv {
height: 90vH;
width: 50%;
position: absolute;
bottom: 0;
}
+11 -9
View File
@@ -22,19 +22,24 @@
*/
import React from 'react';
import './BlocklyComponent.css';
import Blockly from 'blockly/core';
//import locale from 'blockly/msg/en';
import locale from 'blockly/msg/en';
import 'blockly/blocks';
import Toolbox from './toolbox/Toolbox';
//Blockly.setLocale(locale);
import { Card } from '@material-ui/core';
Blockly.setLocale(locale);
class BlocklyComponent extends React.Component {
constructor(props) {
super(props);
this.blocklyDiv = React.createRef();
this.toolbox = React.createRef();
this.state = {workspace: undefined};
}
componentDidMount() {
@@ -46,6 +51,7 @@ class BlocklyComponent extends React.Component {
...rest
},
);
this.setState({workspace: this.primaryWorkspace})
if (initialXml) {
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(initialXml), this.primaryWorkspace);
@@ -61,13 +67,9 @@ class BlocklyComponent extends React.Component {
}
render() {
const { children } = this.props;
return <React.Fragment>
<div ref={this.blocklyDiv} id="blocklyDiv" />
<xml xmlns="https://developers.google.com/blockly/xml" is="blockly" style={{ display: 'none' }} ref={this.toolbox}>
{children}
</xml>
<Card ref={this.blocklyDiv} id="blocklyDiv" style={this.props.style ? this.props.style : {}}/>
<Toolbox toolbox={this.toolbox} workspace={this.state.workspace} />
</React.Fragment>;
}
}
+75
View File
@@ -0,0 +1,75 @@
import React, { Component } from 'react';
import * as Blockly from 'blockly/core';
class BlocklySvg extends Component {
constructor(props) {
super(props);
this.state = {
svg: ''
};
}
componentDidMount() {
this.getSvg();
}
componentDidUpdate(props) {
if(props.initialXml !== this.props.initialXml){
this.getSvg();
}
}
getSvg = () => {
const workspace = Blockly.getMainWorkspace();
workspace.clear();
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(this.props.initialXml), workspace);
var canvas = workspace.svgBlockCanvas_.cloneNode(true);
if (canvas.children[0] !== undefined) {
canvas.removeAttribute("transform");
// does not work in react
// var cssContent = Blockly.Css.CONTENT.join('');
var cssContent = '';
for (var i = 0; i < document.getElementsByTagName('style').length; i++) {
if(/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)){
cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.');
}
}
// ensure that fill-opacity is 1, because there cannot be a replacing
// https://github.com/google/blockly/pull/3431/files#diff-00254795773903d3c0430915a68c9521R328
cssContent += `.blocklyPath {
fill-opacity: 1;
}
.blocklyPathDark {
display: flex;
}
.blocklyPathLight {
display: flex;
} `;
var css = '<defs><style type="text/css" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[' + cssContent + ']]></style></defs>';
var bbox = document.getElementsByClassName("blocklyBlockCanvas")[0].getBBox();
var content = new XMLSerializer().serializeToString(canvas);
var xml = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}">
${css}">${content}</svg>`;
this.setState({svg: xml});
}
}
render() {
return (
<div
style={{display: 'flex', justifyContent: 'center', transform: 'scale(0.8) translate(0, calc(100% * -0.2 / 2))'}}
dangerouslySetInnerHTML={{ __html: this.state.svg }}
/>
);
};
}
export default BlocklySvg;
+97
View File
@@ -0,0 +1,97 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { onChangeWorkspace, clearStats } from '../../actions/workspaceActions';
// import * as De from 'blockly/msg/de';
import {De} from './msg/de';
import BlocklyComponent from './BlocklyComponent';
import BlocklySvg from './BlocklySvg';
import * as Blockly from 'blockly/core';
import './blocks/index';
import './generator/index';
import { initialXml } from './initialXml.js';
class BlocklyWindow extends Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
Blockly.setLocale(De);
}
componentDidMount() {
const workspace = Blockly.getMainWorkspace();
this.props.onChangeWorkspace({});
this.props.clearStats();
workspace.addChangeListener((event) => {
this.props.onChangeWorkspace(event);
// switch on that a block is displayed disabled or not depending on whether it is correctly connected
// for SVG display, a deactivated block in the display is undesirable
if (this.props.blockDisabled) {
Blockly.Events.disableOrphans(event);
}
});
Blockly.svgResize(workspace);
}
componentDidUpdate(props) {
const workspace = Blockly.getMainWorkspace();
var xml = this.props.initialXml;
// if svg is true, then the update process is done in the BlocklySvg component
if (props.initialXml !== xml && !this.props.svg) {
// guarantees that the current xml-code (this.props.initialXml) is rendered
workspace.clear();
if (!xml) xml = initialXml;
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace);
}
Blockly.svgResize(workspace);
}
render() {
return (
<div>
<BlocklyComponent ref={this.simpleWorkspace}
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false}
trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true}
renderer='geras'
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom
controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true,
wheel: false,
startScale: 1,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.2
}}
grid={this.props.grid !== undefined && !this.props.grid ? {} :
{ // https://developers.google.com/blockly/guides/configure/web/grid
spacing: 20,
length: 1,
colour: '#4EAF47', // senseBox-green
snap: false
}}
media={'/media/blockly/'}
move={this.props.move !== undefined && !this.props.move ? {} :
{ // https://developers.google.com/blockly/guides/configure/web/move
scrollbars: true,
drag: true,
wheel: false
}}
initialXml={this.props.initialXml ? this.props.initialXml : initialXml}
>
</BlocklyComponent >
{this.props.svg && this.props.initialXml ? <BlocklySvg initialXml={this.props.initialXml} /> : null}
</div>
);
};
}
BlocklyWindow.propTypes = {
onChangeWorkspace: PropTypes.func.isRequired,
clearStats: PropTypes.func.isRequired
};
export default connect(null, { onChangeWorkspace, clearStats })(BlocklyWindow);
+61
View File
@@ -0,0 +1,61 @@
import Blockly from 'blockly/core';
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
import { getColour } from '../helpers/colour';
Blockly.Blocks['io_tone'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_SETTONE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), "TONEPIN");
this.appendValueInput("FREQUENCY")
.setCheck(Types.getCompatibleTypes('int'))
.appendField(Blockly.Msg.ARD_TONEFREQ);
this.appendDummyInput()
.appendField("Hz");
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(getColour().audio);
this.setTooltip(Blockly.Msg.ARD_TONE_TIP);
this.setHelpUrl('https://www.arduino.cc/en/Reference/tone');
},
/**
* Called whenever anything on the workspace changes.
* It checks frequency values and sets a warning if out of range.
* @this Blockly.Block
*/
onchange: function (event) {
if (!this.workspace || event.type === Blockly.Events.MOVE ||
event.type === Blockly.Events.UI) {
return; // Block deleted or irrelevant event
}
var freq = Blockly.Arduino.valueToCode(
this, "FREQUENCY", Blockly.Arduino.ORDER_ATOMIC)
if (freq < 31 || freq > 65535) {
this.setWarningText(Blockly.Msg.ARD_TONE_WARNING, 'io_tone');
} else {
this.setWarningText(null, 'io_tone');
}
}
};
Blockly.Blocks['io_notone'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_NOTONE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), "TONEPIN");
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(getColour().audio);
this.setTooltip(Blockly.Msg.ARD_NOTONE_TIP);
this.setHelpUrl('https://www.arduino.cc/en/Reference/noTone');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Blockly.Types.NUMBER;
}
};
+17
View File
@@ -2,3 +2,20 @@ import './loops';
import './sensebox';
import './logic';
import './sensebox-sensors';
import './sensebox-telegram';
import './sensebox-osem';
import './sensebox-web';
import './sensebox-display';
import './sensebox-lora';
import './sensebox-led';
import './sensebox-sd';
import './text';
import './io';
import './audio';
import './math';
import './map';
import './procedures';
import './time';
import './variables';
import '../helpers/types'
+257
View File
@@ -0,0 +1,257 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Blocks for Arduino Digital and Analogue input and output
* functions. The Arduino function syntax can be found at
* http://arduino.cc/en/Reference/HomePage
*
* TODO: maybe change this to a "PIN" BlocklyType
*/
import Blockly from 'blockly/core';
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
Blockly.Blocks['io_digitalwrite'] = {
/**
* Block for creating a 'set pin' to a state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalWrite');
this.setColour(250);
this.appendValueInput('STATE')
.appendField(Blockly.Msg.ARD_DIGITALWRITE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'PIN')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.BOOLEAN.checkList);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_DIGITALWRITE_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'PIN', 'digitalPins');
}
};
Blockly.Blocks['io_digitalread'] = {
/**
* Block for creating a 'read pin'.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalRead');
this.setColour(250);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_DIGITALREAD)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'PIN');
this.setOutput(true, 'boolean');
this.setTooltip(Blockly.Msg.ARD_DIGITALREAD_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'PIN', 'digitalPins');
}
};
Blockly.Blocks['io_builtin_led'] = {
/**
* Block for setting built-in LED to a state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DigitalWrite');
this.setColour(250);
this.appendValueInput('STATE')
.appendField(Blockly.Msg.ARD_BUILTIN_LED)
.appendField(new Blockly.FieldDropdown(
selectedBoard().builtinLed), 'BUILT_IN_LED')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.BOOLEAN.compatibleTypes);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_BUILTIN_LED_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'BUILT_IN_LED', 'builtinLed');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
},
};
Blockly.Blocks['io_analogwrite'] = {
/**
* Block for creating a 'set pin' to an analogue value.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/AnalogWrite');
this.setColour(250);
this.appendValueInput('NUM')
.appendField(Blockly.Msg.ARD_ANALOGWRITE)
.appendField(new Blockly.FieldDropdown(
selectedBoard().pwmPins), 'PIN')
.appendField(Blockly.Msg.ARD_WRITE_TO)
.setCheck(Types.NUMBER.compatibleTypes);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_ANALOGWRITE_TIP);
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(this, 'PIN', 'pwmPins');
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER;
},
};
Blockly.Blocks['io_analogread'] = {
/**
* Block for reading an analogue input.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/AnalogRead');
this.setColour(250);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_ANALOGREAD)
.appendField(new Blockly.FieldDropdown(
selectedBoard().analogPins), 'PIN');
this.setOutput(true, Types.NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_ANALOGREAD_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
},
/**
* Updates the content of the the pin related fields.
* @this Blockly.Block
*/
updateFields: function () {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(this, 'PIN', 'analogPins');
}
};
Blockly.Blocks['io_highlow'] = {
/**
* Block for creating a pin state.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Constants');
this.setColour(250);
this.appendDummyInput()
.appendField(
new Blockly.FieldDropdown([[Blockly.Msg.ARD_HIGH, 'HIGH'], [Blockly.Msg.ARD_LOW, 'LOW']]),
'STATE');
this.setOutput(true, Types.BOOLEAN.typeId);
this.setTooltip(Blockly.Msg.ARD_HIGHLOW_TIP);
},
/** @return {!string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.BOOLEAN;
}
};
Blockly.Blocks['io_pulsein'] = {
/**
* Block for measuring the duration of a pulse in an input pin.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"type": "math_foo",
"message0": Blockly.Msg.ARD_PULSE_READ,
"args0": [{
"type": "input_value",
"name": "PULSETYPE",
"check": Types.BOOLEAN.compatibleTypes
}, {
"type": "field_dropdown",
"name": "PULSEPIN",
"options": selectedBoard().digitalPins,
}
],
"output": Types.NUMBER.typeId,
"inputsInline": true,
"colour": 250,
"tooltip": Blockly.Msg.ARD_PULSE_TIP,
"helpUrl": 'https://www.arduino.cc/en/Reference/PulseIn'
});
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
Blockly.Blocks['io_pulsetimeout'] = {
/**
* Block for measuring (with a time-out) the duration of a pulse in an input
* pin.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"type": "math_foo",
"message0": Blockly.Msg.ARD_PULSE_READ_TIMEOUT,
"args0": [{
"type": "input_value",
"name": "PULSETYPE",
"check": Types.BOOLEAN.compatibleTypes
}, {
"type": "field_dropdown",
"name": "PULSEPIN",
"options": selectedBoard().digitalPins,
}, {
"type": "input_value",
"name": "TIMEOUT",
"check": Types.NUMBER.compatibleTypes
}
],
"output": Types.NUMBER.typeId,
"inputsInline": true,
"colour": 250,
"tooltip": Blockly.Msg.ARD_PULSETIMEOUT_TIP,
"helpUrl": 'https://www.arduino.cc/en/Reference/PulseIn'
});
},
/** @return {!string} The type of input value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
+445 -38
View File
@@ -1,61 +1,468 @@
import { defineBlocksWithJsonArray } from 'blockly';
import Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types';
import { getCompatibleTypes } from '../helpers/types';
defineBlocksWithJsonArray([
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
// Block for boolean data type: true and false.
{
"type": "logic_boolean",
"message0": "%1",
"args0": [
{
"type": "field_dropdown",
"name": "BOOL",
"options": [
["%{BKY_LOGIC_BOOLEAN_TRUE}", "TRUE"],
["%{BKY_LOGIC_BOOLEAN_FALSE}", "FALSE"]
]
}
],
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}"
},
// Block for if/elseif/else condition.
{
"type": "controls_if",
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
"args0": [
{
"type": "input_value",
"name": "IF0",
"check": Types.getCompatibleTypes('boolean')
}
],
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
"args1": [
{
"type": "input_statement",
"name": "DO0"
}
],
"previousStatement": null,
"nextStatement": null,
"style": "logic_blocks",
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
"mutator": "controls_if_mutator",
"extensions": ["controls_if_tooltip"]
},
// If/else block that does not use a mutator.
{
type: 'control_if',
message0: '%{BKY_CONTROLS_IF_MSG_IF} %1',
args0: [
"type": "controls_ifelse",
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
"args0": [
{
type: 'input_value',
name: 'IF0',
check: 'Boolean'
"type": "input_value",
"name": "IF0",
"check": Types.getCompatibleTypes('boolean')
}
],
message1: '%{BKY_CONTROLS_IF_MSG_THEN} %1',
args1: [
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
"args1": [
{
type: 'input_statement',
name: 'DO0'
"type": "input_statement",
"name": "DO0"
}
],
previousStatement: null,
nextStatement: null,
colour: '#b063c5',
tooltip: '%{BKYCONTROLS_IF_TOOLTIP_2}',
helpUrl: '%{BKY_CONTROLS_IF_HELPURL}',
extensions: ['controls_if_tooltip']
"message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1",
"args2": [
{
"type": "input_statement",
"name": "ELSE"
}
],
"previousStatement": null,
"nextStatement": null,
"style": "logic_blocks",
"tooltip": "%{BKYCONTROLS_IF_TOOLTIP_2}",
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
"extensions": ["controls_if_tooltip"]
},
// Block for comparison operator.
{
"type": "logic_compare",
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A"
},
{
type: 'controls_ifelse',
message0: '%{BKY_CONTROLS_IF_MSG_IF} %1',
args0: [
"type": "field_dropdown",
"name": "OP",
"options": [
["=", "EQ"],
["\u2260", "NEQ"],
["\u200F<", "LT"],
["\u200F\u2264", "LTE"],
["\u200F>", "GT"],
["\u200F\u2265", "GTE"]
]
},
{
type: 'input_value',
name: 'IF0',
check: 'Boolean'
"type": "input_value",
"name": "B"
}
],
message1: '%{BKY_CONTROLS_IF_MSG_THEN} %1',
args1: [
"inputsInline": true,
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"helpUrl": "%{BKY_LOGIC_COMPARE_HELPURL}",
"extensions": ["logic_compare", "logic_op_tooltip"]
},
// Block for logical operations: 'and', 'or'.
{
type: 'input_statement',
name: 'DO0'
"type": "logic_operation",
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A",
"check": Types.getCompatibleTypes('boolean')
},
{
"type": "field_dropdown",
"name": "OP",
"options": [
["%{BKY_LOGIC_OPERATION_AND}", "AND"],
["%{BKY_LOGIC_OPERATION_OR}", "OR"]
]
},
{
"type": "input_value",
"name": "B",
"check": Types.getCompatibleTypes('boolean')
}
],
message2: '%{BKY_CONTROLS_IF_MSG_ELSE} %1',
args2: [
"inputsInline": true,
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"helpUrl": "%{BKY_LOGIC_OPERATION_HELPURL}",
"extensions": ["logic_op_tooltip"]
},
// Block for negation.
{
type: 'input_statement',
name: 'ELSE'
"type": "logic_negate",
"message0": "%{BKY_LOGIC_NEGATE_TITLE}",
"args0": [
{
"type": "input_value",
"name": "BOOL",
"check": Types.getCompatibleTypes('boolean'),
}
],
previousStatement: null,
nextStatement: null,
colour: '#b063c5',
tooltip: '%{BKYCONTROLS_IF_TOOLTIP_2}',
helpUrl: '%{BKY_CONTROLS_IF_HELPURL}',
extensions: ['controls_if_tooltip']
"output": Types.BOOLEAN.typeName,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_NEGATE_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_NEGATE_HELPURL}"
},
// Block for null data type.
{
"type": "logic_null",
"message0": "%{BKY_LOGIC_NULL}",
"output": null,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_NULL_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_NULL_HELPURL}"
},
// Block for ternary operator.
{
"type": "logic_ternary",
"message0": "%{BKY_LOGIC_TERNARY_CONDITION} %1",
"args0": [
{
"type": "input_value",
"name": "IF",
"check": Types.getCompatibleTypes('boolean'),
}
],
"message1": "%{BKY_LOGIC_TERNARY_IF_TRUE} %1",
"args1": [
{
"type": "input_value",
"name": "THEN"
}
],
"message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
"args2": [
{
"type": "input_value",
"name": "ELSE"
}
],
"output": null,
"style": "logic_blocks",
"tooltip": "%{BKY_LOGIC_TERNARY_TOOLTIP}",
"helpUrl": "%{BKY_LOGIC_TERNARY_HELPURL}",
"extensions": ["logic_ternary"]
}
]); // END JSON EXTRACT (Do not delete this comment.)
Blockly.defineBlocksWithJsonArray([ // Mutator blocks. Do not extract.
// Block representing the if statement in the controls_if mutator.
{
"type": "controls_if_if",
"message0": "%{BKY_CONTROLS_IF_IF_TITLE_IF}",
"nextStatement": null,
"enableContextMenu": false,
"style": "logic_blocks",
"tooltip": "%{BKY_CONTROLS_IF_IF_TOOLTIP}"
},
// Block representing the else-if statement in the controls_if mutator.
{
"type": "controls_if_elseif",
"message0": "%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",
"previousStatement": null,
"nextStatement": null,
"enableContextMenu": false,
"style": "logic_blocks",
"tooltip": "%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"
},
// Block representing the else statement in the controls_if mutator.
{
"type": "controls_if_else",
"message0": "%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",
"previousStatement": null,
"enableContextMenu": false,
"style": "logic_blocks",
"tooltip": "%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"
}
]);
Blockly.Blocks['logic_compare'] = {
/**
* Block for comparison operator.
* @this Blockly.Block
*/
init: function () {
var OPERATORS = this.RTL ? [
['=', 'EQ'],
['\u2260', 'NEQ'],
['>', 'LT'],
['\u2265', 'LTE'],
['<', 'GT'],
['\u2264', 'GTE']
] : [
['=', 'EQ'],
['\u2260', 'NEQ'],
['<', 'LT'],
['\u2264', 'LTE'],
['>', 'GT'],
['\u2265', 'GTE']
];
this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);
this.setColour(getColour().logic);
this.setOutput(true, Types.BOOLEAN.typeName);
this.appendValueInput('A');
this.appendValueInput('B')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
this.setInputsInline(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'EQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,
'NEQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,
'LT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,
'LTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,
'GT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,
'GTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE
};
return TOOLTIPS[op];
});
},
/**
* Called whenever anything on the workspace changes.
* Prevent mismatched types from being compared.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var blockA = this.getInputTargetBlock('A');
var blockB = this.getInputTargetBlock('B');
if (blockA === null && blockB === null) {
this.getInput('A').setCheck(null);
this.getInput('B').setCheck(null);
}
if (blockA !== null && blockB === null) {
this.getInput('A').setCheck(getCompatibleTypes(blockA.outputConnection.check_[0]));
this.getInput('B').setCheck(getCompatibleTypes(blockA.outputConnection.check_[0]));
}
if (blockB !== null && blockA === null) {
this.getInput('B').setCheck(getCompatibleTypes(blockB.outputConnection.check_[0]));
this.getInput('A').setCheck(getCompatibleTypes(blockB.outputConnection.check_[0]));
}
}
};
Blockly.Blocks['switch_case'] = {
init: function () {
this.setColour(getColour().logic);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendValueInput('CONDITION')
.appendField(Blockly.Msg.cases_switch);
this.appendValueInput('CASECONDITION0')
.appendField(Blockly.Msg.cases_condition);
this.appendStatementInput('CASE0')
.appendField(Blockly.Msg.cases_do);
this.setMutator(new Blockly.Mutator(['case_incaseof', 'case_default']));
this.setTooltip('Does something if the condition is true. If there isn\'t a matching case the default function will be executed.');
this.caseCount_ = 0;
this.defaultCount_ = 0;
},
mutationToDom: function () {
if (!this.caseCount_ && !this.defaultCount_) {
return null;
}
var container = document.createElement('mutation');
if (this.caseCount_) {
container.setAttribute('case', this.caseCount_);
}
if (this.defaultCount_) {
container.setAttribute('default', 1);
}
return container;
},
domToMutation: function (xmlElement) {
this.caseCount_ = parseInt(xmlElement.getAttribute('case'), 10);
this.defaultCount_ = parseInt(xmlElement.getAttribute('default'), 10);
for (var x = 0; x <= this.caseCount_; x++) {
this.appendValueInput('CASECONDITION' + x)
.appendField(Blockly.Msg.cases_condition);
this.appendStatementInput('CASE' + x)
.appendField(Blockly.Msg.cases_do);
}
if (this.defaultCount_) {
this.appendStatementInput('ONDEFAULT')
.appendField('default');
}
},
decompose: function (workspace) {
var containerBlock = workspace.newBlock('control_case');
containerBlock.initSvg();
var connection = containerBlock.getInput('STACK').connection;
for (var x = 1; x <= this.caseCount_; x++) {
var caseBlock = workspace.newBlock('case_incaseof');
caseBlock.initSvg();
connection.connect(caseBlock.previousConnection);
connection = caseBlock.nextConnection;
}
if (this.defaultCount_) {
var defaultBlock = Blockly.Block.obtain(workspace, 'case_default');
defaultBlock.initSvg();
connection.connect(defaultBlock.previousConnection);
}
return containerBlock;
},
compose: function (containerBlock) {
//Disconnect all input blocks and remove all inputs.
if (this.defaultCount_) {
this.removeInput('ONDEFAULT');
}
this.defaultCount_ = 0;
for (var x = this.caseCount_; x > 0; x--) {
this.removeInput('CASECONDITION' + x);
this.removeInput('CASE' + x);
}
this.caseCount_ = 0;
var caseBlock = containerBlock.getInputTargetBlock('STACK');
while (caseBlock) {
switch (caseBlock.type) {
case 'case_incaseof':
this.caseCount_++;
var caseconditionInput = this.appendValueInput('CASECONDITION' + this.caseCount_)
.appendField(Blockly.Msg.cases_condition);
var caseInput = this.appendStatementInput('CASE' + this.caseCount_)
.appendField(Blockly.Msg.cases_do);
if (caseBlock.valueConnection_) {
caseconditionInput.connection.connect(caseBlock.valueConnection_);
}
if (caseBlock.statementConnection_) {
caseInput.connection.connect(caseBlock.statementConnection_);
}
break;
case 'case_default':
this.defaultCount_++;
var defaultInput = this.appendStatementInput('ONDEFAULT')
.appendField('default');
if (caseBlock.statementConnection_) {
defaultInput.connection.connect(caseBlock.statementConnection_);
}
break;
default:
throw new Error('Unknown block type.');
}
caseBlock = caseBlock.nextConnection &&
caseBlock.nextConnection.targetBlock();
}
},
saveConnections: function (containerBlock) {
var caseBlock = containerBlock.getInputTargetBlock('STACK');
var x = 1;
while (caseBlock) {
switch (caseBlock.type) {
case 'case_incaseof':
var caseconditionInput = this.getInput('CASECONDITION' + x);
var caseInput = this.getInput('CASE' + x);
caseBlock.valueConnection_ = caseconditionInput && caseconditionInput.connection.targetConnection;
caseBlock.statementConnection_ = caseInput && caseInput.connection.targetConnection;
x++;
break;
case 'case_default':
var defaultInput = this.getInput('ONDEFAULT');
caseBlock.satementConnection_ = defaultInput && defaultInput.connection.targetConnection;
break;
default:
throw new Error('Unknown block type');
}
caseBlock = caseBlock.nextConnection &&
caseBlock.nextConnection.targetBlock();
}
}
};
Blockly.Blocks['control_case'] = {
init: function () {
this.setColour(getColour().logic);
this.appendDummyInput()
.appendField(Blockly.Msg.cases_switch);
this.appendStatementInput('STACK');
this.setTooltip('--Placeholder--');
this.contextMenu = false;
}
};
Blockly.Blocks['case_incaseof'] = {
init: function () {
this.setColour(getColour().logic);
this.appendDummyInput()
.appendField(Blockly.Msg.cases_add);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('--Placeholder--');
this.contextMenu = false;
}
};
Blockly.Blocks['case_default'] = {
init: function () {
this.setColour(getColour().logic);
this.appendValueInput('default')
.appendField('default');
this.setPreviousStatement(true);
this.setNextStatement(false);
this.setTooltip('This function will run if there aren\'t any matching cases.');
this.contextMenu = false;
}
};
+195 -35
View File
@@ -1,51 +1,211 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour';
import { getCompatibleTypes } from '../helpers/types'
Blockly.defineBlocksWithJsonArray([
Blockly.Blocks['controls_whileUntil'] = {
/**
* Block for 'do while/until' loop.
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, 'WHILE'],
[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, 'UNTIL']];
this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
this.setColour(getColour().loops);
this.appendValueInput('BOOL')
.setCheck(getCompatibleTypes(Boolean))
.appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE');
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
this.setPreviousStatement(true);
this.setNextStatement(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('MODE');
var TOOLTIPS = {
'WHILE': Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,
'UNTIL': Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL
};
return TOOLTIPS[op];
});
}
};
Blockly.Blocks['controls_for'] = {
/**
* Block for 'for' loop.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_FOR_TITLE,
"args0": [
{
type: 'controls_for',
message0: 'count with %1 from %2 to %3 by adding %4',
args0: [
{
type: 'field_variable',
name: 'VAR',
variable: null,
variableTypes: ['Number'],
defaultType: 'Number',
createNewVariable: true,
showOnlyVariableAssigned: false,
"type": "field_variable",
"name": "VAR",
"variable": null
},
{
type: 'input_value',
name: 'FROM',
check: 'Number',
align: 'RIGHT',
"type": "input_value",
"name": "FROM",
"check": getCompatibleTypes(Number),
"align": "RIGHT"
},
{
type: 'input_value',
name: 'TO',
check: 'Number',
align: 'RIGHT',
"type": "input_value",
"name": "TO",
"check": getCompatibleTypes(Number),
"align": "RIGHT"
},
{
type: 'input_value',
name: 'BY',
check: 'Number',
align: 'RIGHT',
},
"type": "input_value",
"name": "BY",
"check": getCompatibleTypes(Number),
"align": "RIGHT"
}
],
message1: '%{BKY_CONTROLS_REPEAT_INPUT_DO} %1',
args1: [
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"helpUrl": Blockly.Msg.CONTROLS_FOR_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
}
};
Blockly.Blocks['controls_forEach'] = {
/**
* Block for 'for each' loop.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_FOREACH_TITLE,
"args0": [
{
type: 'input_statement',
name: 'DO',
"type": "field_variable",
"name": "VAR",
"variable": null
},
{
"type": "input_value",
"name": "LIST",
"check": getCompatibleTypes(Array)
}
],
inputsInline: false,
previousStatement: null,
nextStatement: null,
helpUrl: '%{BKY_CONTROLS_FOR_HELPURL}',
extensions: ['contextMenu_newGetVariableBlock', 'controls_for_tooltip'],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"helpUrl": Blockly.Msg.CONTROLS_FOREACH_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
},
customContextMenu: Blockly.Blocks['controls_for'].customContextMenu,
/** @returns {!string} The type of the variable used in this block */
getVarType: function (varName) {
return Blockly.Types.NUMBER;
}
};
Blockly.Blocks['controls_flow_statements'] = {
/**
* Block for flow statements: continue, break.
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, 'BREAK'],
[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, 'CONTINUE']];
this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);
this.setColour(getColour().loops);
this.appendDummyInput()
.appendField(new Blockly.FieldDropdown(OPERATORS), 'FLOW');
this.setPreviousStatement(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var op = thisBlock.getFieldValue('FLOW');
var TOOLTIPS = {
'BREAK': Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK,
'CONTINUE': Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE
};
return TOOLTIPS[op];
});
},
]);
/**
* Called whenever anything on the workspace changes.
* Add warning if this flow block is not nested inside a loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
/**
* List of block types that are loops and thus do not need warnings.
* To add a new loop type add this to your code:
* Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop');
*/
LOOP_TYPES: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach',
'controls_for', 'controls_whileUntil']
};
Blockly.Blocks['controls_repeat_ext'] = {
/**
* Block for repeat n times (external number).
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.CONTROLS_REPEAT_TITLE,
"args0": [
{
"type": "input_value",
"name": "TIMES",
"check": getCompatibleTypes(Number),
}
],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().loops,
"tooltip": Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
"helpUrl": Blockly.Msg.CONTROLS_REPEAT_HELPURL
});
this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
}
};
+50
View File
@@ -0,0 +1,50 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Block for the Arduino map functionality.
* The Arduino built in functions syntax can be found at:
* http://arduino.cc/en/Reference/HomePage
*
* TODO: This block can be improved to set the new range properly.
*/
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
Blockly.Blocks['base_map'] = {
/**
* Block for creating a the map function.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/map');
this.setColour(getColour().math);
this.appendValueInput('NUM')
.appendField(Blockly.Msg.ARD_MAP)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('FMIN')
.appendField(Blockly.Msg.ARD_MAP_FROMMIN)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('FMAX')
.appendField(Blockly.Msg.ARD_MAP_FROMMAX)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('DMIN')
.appendField(Blockly.Msg.ARD_MAP_TOMIN)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('DMAX')
.appendField(Blockly.Msg.ARD_MAP_TOMAX)
.setCheck(Types.NUMBER.compatibleTypes);
this.setOutput(true);
this.setInputsInline(false);
this.setTooltip(Blockly.Msg.ARD_MAP_TIP);
},
/** @return {string} The type of return value for the block, an integer. */
getBlockType: function () {
return Types.NUMBER.typeId;
}
};
+528
View File
@@ -0,0 +1,528 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
Blockly.Blocks['math_number'] = {
/**
* Block for numeric value.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);
this.setColour(getColour().math);
this.appendDummyInput()
.appendField(
new Blockly.FieldTextInput(
'0', Blockly.FieldTextInput.numberValidator),
'NUM');
this.setOutput(true, Types.NUMBER.typeName);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
// Number block is trivial. Use tooltip of parent block if it exists.
this.setTooltip(function () {
var parent = thisBlock.getParent();
return (parent && parent.getInputsInline() && parent.tooltip) ||
Blockly.Msg.MATH_NUMBER_TOOLTIP;
});
}
};
Blockly.Blocks['math_arithmetic'] = {
/**
* Block for basic arithmetic operator.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2 %3",
"args0": [
{
"type": "input_value",
"name": "A",
"check": Types.getCompatibleTypes('int')
},
{
"type": "field_dropdown",
"name": "OP",
"options":
[[Blockly.Msg.MATH_ADDITION_SYMBOL, 'ADD'],
[Blockly.Msg.MATH_SUBTRACTION_SYMBOL, 'MINUS'],
[Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, 'MULTIPLY'],
[Blockly.Msg.MATH_DIVISION_SYMBOL, 'DIVIDE'],
[Blockly.Msg.MATH_POWER_SYMBOL, 'POWER']]
},
{
"type": "input_value",
"name": "B",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_ARITHMETIC_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
};
return TOOLTIPS[mode];
});
}
//TODO: a getBlockType based on the two input types following C++ rules
};
Blockly.Blocks['math_single'] = {
/**
* Block for advanced math operators with single operand.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_SINGLE_OP_ROOT, 'ROOT'],
[Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, 'ABS'],
['-', 'NEG'],
['ln', 'LN'],
['log10', 'LOG10'],
['e^', 'EXP'],
['10^', 'POW10']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_SINGLE_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'ROOT': Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT,
'ABS': Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,
'NEG': Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,
'LN': Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,
'LOG10': Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,
'EXP': Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,
'POW10': Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10
};
return TOOLTIPS[mode];
});
}
};
Blockly.Blocks['math_trig'] = {
/**
* Block for trigonometry operators.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_TRIG_SIN, 'SIN'],
[Blockly.Msg.MATH_TRIG_COS, 'COS'],
[Blockly.Msg.MATH_TRIG_TAN, 'TAN'],
[Blockly.Msg.MATH_TRIG_ASIN, 'ASIN'],
[Blockly.Msg.MATH_TRIG_ACOS, 'ACOS'],
[Blockly.Msg.MATH_TRIG_ATAN, 'ATAN']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_TRIG_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'SIN': Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,
'COS': Blockly.Msg.MATH_TRIG_TOOLTIP_COS,
'TAN': Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,
'ASIN': Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,
'ACOS': Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,
'ATAN': Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN
};
return TOOLTIPS[mode];
});
}
};
Blockly.Blocks['math_constant'] = {
/**
* Block for constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1",
"args0": [
{
"type": "field_dropdown",
"name": "CONSTANT",
"options": [
['\u03c0', 'PI'],
['e', 'E'],
['\u03c6', 'GOLDEN_RATIO'],
['sqrt(2)', 'SQRT2'],
['sqrt(\u00bd)', 'SQRT1_2'],
['\u221e', 'INFINITY']
]
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_CONSTANT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_CONSTANT_HELPURL
});
}
};
Blockly.Blocks['math_number_property'] = {
/**
* Block for checking if a number is even, odd, prime, whole, positive,
* negative or if it is divisible by certain number.
* @this Blockly.Block
*/
init: function () {
var PROPERTIES =
[[Blockly.Msg.MATH_IS_EVEN, 'EVEN'],
[Blockly.Msg.MATH_IS_ODD, 'ODD'],
[Blockly.Msg.MATH_IS_PRIME, 'PRIME'],
[Blockly.Msg.MATH_IS_WHOLE, 'WHOLE'],
[Blockly.Msg.MATH_IS_POSITIVE, 'POSITIVE'],
[Blockly.Msg.MATH_IS_NEGATIVE, 'NEGATIVE'],
[Blockly.Msg.MATH_IS_DIVISIBLE_BY, 'DIVISIBLE_BY']];
this.setColour(getColour().math);
this.appendValueInput('NUMBER_TO_CHECK')
.setCheck(Types.getCompatibleTypes('int'));
var dropdown = new Blockly.FieldDropdown(PROPERTIES, function (option) {
var divisorInput = (option === 'DIVISIBLE_BY');
this.sourceBlock_.updateShape_(divisorInput);
});
this.appendDummyInput()
.appendField(dropdown, 'PROPERTY');
this.setInputsInline(true);
this.setOutput(true, Types.BOOLEAN.typeName);
this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP);
},
/**
* Create XML to represent whether the 'divisorInput' should be present.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var divisorInput = (this.getFieldValue('PROPERTY') === 'DIVISIBLE_BY');
container.setAttribute('divisor_input', divisorInput);
return container;
},
/**
* Parse XML to restore the 'divisorInput'.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
var divisorInput = (xmlElement.getAttribute('divisor_input') === 'true');
this.updateShape_(divisorInput);
},
/**
* Modify this block to have (or not have) an input for 'is divisible by'.
* @param {boolean} divisorInput True if this block has a divisor input.
* @private
* @this Blockly.Block
*/
updateShape_: function (divisorInput) {
// Add or remove a Value Input.
var inputExists = this.getInput('DIVISOR');
if (divisorInput) {
if (!inputExists) {
this.appendValueInput('DIVISOR')
.setCheck(Types.getCompatibleTypes('int'));
}
} else if (inputExists) {
this.removeInput('DIVISOR');
}
}
};
Blockly.Blocks['math_change'] = {
/**
* Block for adding to a variable in place.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_CHANGE_TITLE,
"args0": [
{
"type": "field_variable",
"name": "VAR",
"variable": Blockly.Msg.MATH_CHANGE_TITLE_ITEM
},
{
"type": "input_value",
"name": "DELTA",
"check": Types.getCompatibleTypes('int'),
"align": "RIGHT"
}
],
"previousStatement": null,
"nextStatement": null,
"colour": getColour().math,
"helpUrl": Blockly.Msg.MATH_CHANGE_HELPURL
});
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function () {
return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace('%1',
thisBlock.getFieldValue('VAR'));
});
}
};
Blockly.Blocks['math_round'] = {
/**
* Block for rounding functions.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": "%1 %2",
"args0": [
{
"type": "field_dropdown",
"name": "OP",
"options": [
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, 'ROUND'],
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, 'ROUNDUP'],
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, 'ROUNDDOWN']
]
},
{
"type": "input_value",
"name": "NUM",
"check": Types.getCompatibleTypes('float')
}
],
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_ROUND_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_ROUND_HELPURL
});
}
};
Blockly.Blocks['math_on_list'] = {
/**
* Block for evaluating a list of numbers to return sum, average, min, max,
* etc. Some functions also work on text (min, max, mode, median).
* @this Blockly.Block
*/
init: function () {
var OPERATORS =
[[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, 'SUM'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, 'MIN'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, 'MAX'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, 'AVERAGE'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, 'MEDIAN'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, 'MODE'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, 'STD_DEV'],
[Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, 'RANDOM']];
// Assign 'this' to a variable for use in the closures below.
var thisBlock = this;
this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);
this.setColour(getColour().math);
this.setOutput(true, Types.NUMBER.typeName);
var dropdown = new Blockly.FieldDropdown(OPERATORS, function (newOp) {
thisBlock.updateType_(newOp);
});
this.appendValueInput('LIST')
.setCheck(Types.getCompatibleTypes('array'))
.appendField(dropdown, 'OP');
this.setTooltip(function () {
var mode = thisBlock.getFieldValue('OP');
var TOOLTIPS = {
'SUM': Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,
'MIN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,
'MAX': Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,
'AVERAGE': Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,
'MEDIAN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN,
'MODE': Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,
'STD_DEV': Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,
'RANDOM': Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM
};
return TOOLTIPS[mode];
});
},
/**
* Modify this block to have the correct output type.
* @param {string} newOp Either 'MODE' or some op than returns a number.
* @private
* @this Blockly.Block
*/
updateType_: function (newOp) {
if (newOp === 'MODE') {
this.outputConnection.setCheck(Types.getCompatibleTypes('array'));
} else {
this.outputConnection.setCheck(Types.getCompatibleTypes('int'));
}
},
/**
* Create XML to represent the output type.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
container.setAttribute('op', this.getFieldValue('OP'));
return container;
},
/**
* Parse XML to restore the output type.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
this.updateType_(xmlElement.getAttribute('op'));
}
//TODO: a getBlockType once the list code is finished.
};
Blockly.Blocks['math_modulo'] = {
/**
* Block for remainder of a division.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_MODULO_TITLE,
"args0": [
{
"type": "input_value",
"name": "DIVIDEND",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "DIVISOR",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_MODULO_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_MODULO_HELPURL
});
}
};
Blockly.Blocks['math_constrain'] = {
/**
* Block for constraining a number between two limits.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_CONSTRAIN_TITLE,
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "LOW",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "HIGH",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_CONSTRAIN_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_CONSTRAIN_HELPURL
});
}
//TODO: a getBlockType of the same type as the inputs.
};
Blockly.Blocks['math_random_int'] = {
/**
* Block for random integer between [X] and [Y].
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_RANDOM_INT_TITLE,
"args0": [
{
"type": "input_value",
"name": "FROM",
"check": Types.getCompatibleTypes('int')
},
{
"type": "input_value",
"name": "TO",
"check": Types.getCompatibleTypes('int')
}
],
"inputsInline": true,
"output": Types.NUMBER.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_RANDOM_INT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_RANDOM_INT_HELPURL
});
}
};
Blockly.Blocks['math_random_float'] = {
/**
* Block for random fraction between 0 and 1.
* @this Blockly.Block
*/
init: function () {
this.jsonInit({
"message0": Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM,
"output": Types.DECIMAL.typeName,
"colour": getColour().math,
"tooltip": Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP,
"helpUrl": Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL
});
}
};
@@ -0,0 +1,38 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Block for the Arduino functions.
* The Arduino built in functions syntax can be found at:
* https://arduino.cc/en/Reference/HomePage
*/
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
Blockly.Blocks['arduino_functions'] = {
/**
* Block for defining the Arduino setup() and loop() functions.
* @this Blockly.Block
*/
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_FUN_RUN_SETUP);
this.appendStatementInput('SETUP_FUNC');
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_FUN_RUN_LOOP);
this.appendStatementInput('LOOP_FUNC');
this.setInputsInline(false);
this.setColour(getColour().procedures);
this.setTooltip(Blockly.Msg.ARD_FUN_RUN_TIP);
this.setHelpUrl('https://arduino.cc/en/Reference/Loop');
this.contextMenu = false;
},
/** @return {!boolean} True if the block instance is in the workspace. */
getArduinoLoopsInstance: function () {
return true;
}
};
@@ -0,0 +1,254 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types'
import { FieldSlider } from '@blockly/field-slider';
Blockly.Blocks['sensebox_display_beginDisplay'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_beginDisplay)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_display_beginDisplay_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
Blockly.Blocks['sensebox_display_clearDisplay'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_clearDisplay)
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_display_clearDisplay_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
Blockly.Blocks['sensebox_display_printDisplay'] = {
init: function (block) {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_color)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_display_white, "WHITE,BLACK"], [Blockly.Msg.senseBox_display_black, "BLACK,WHITE"]]), "COLOR");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_setSize)
.appendField(new FieldSlider(1, 1, 4), "SIZE");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.appendField(new FieldSlider(0, 0, 64), "X");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.appendField(new FieldSlider(0, 0, 128), "Y");
this.appendValueInput('printDisplay')
.appendField(Blockly.Msg.senseBox_display_printDisplay_value)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
let variableName = this.getField('COLOR');
console.log(variableName.getValue());
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tip);
this.setHelpUrl('https://sensebox.de/books');
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_display_show'],
};
Blockly.Blocks['sensebox_display_plotDisplay'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_plotDisplay)
this.appendValueInput("Title", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotTitle);
this.appendValueInput("YLabel", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotYLabel);
this.appendValueInput("XLabel", 'Text')
.appendField(Blockly.Msg.senseBox_display_plotXLabel);
this.appendValueInput("XRange1", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXRange1);
this.appendValueInput("XRange2", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXRange2)
this.appendValueInput("YRange1", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYRange1);
this.appendValueInput("YRange2", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYRange2);
this.setInputsInline(false);
this.appendValueInput("XTick", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotXTick);
this.appendValueInput("YTick", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotYTick);
this.appendValueInput("TimeFrame", 'Number')
.appendField(Blockly.Msg.senseBox_display_plotTimeFrame);
this.appendValueInput('plotDisplay')
.appendField(Blockly.Msg.senseBox_display_printDisplay_value)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_display_printDisplay_tip);
this.setHelpUrl('https://sensebox.de/books');
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_display_show'],
};
Blockly.Blocks['sensebox_display_show'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_show);
this.appendStatementInput('SHOW');
this.setTooltip(Blockly.Msg.sensebox_display_show_tip);
this.setHelpUrl('');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks['sensebox_display_fillCircle'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_fillCircle);
this.appendValueInput('X')
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Y')
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Radius')
.appendField(Blockly.Msg.sensebox_display_fillCircle_radius)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendDummyInput('fill')
.appendField(Blockly.Msg.senseBox_display_filled)
.appendField(new Blockly.FieldCheckbox("TRUE"), "FILL");
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_display_show'],
};
Blockly.Blocks['sensebox_display_drawRectangle'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.sensebox_display_drawRectangle);
this.appendValueInput('X')
.appendField(Blockly.Msg.senseBox_display_printDisplay_x)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('Y')
.appendField(Blockly.Msg.senseBox_display_printDisplay_y)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('width')
.appendField(Blockly.Msg.sensebox_display_drawRectangle_width)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendValueInput('height')
.appendField(Blockly.Msg.sensebox_display_drawRectangle_height)
.setCheck(Types.NUMBER.compatibleTypes);
this.appendDummyInput('fill')
.appendField(Blockly.Msg.senseBox_display_filled)
.appendField(new Blockly.FieldCheckbox("TRUE"), "FILL");
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_display_show'],
};
@@ -0,0 +1,44 @@
import * as Blockly from 'blockly';
import { FieldSlider } from '@blockly/field-slider';
import { getColour } from '../helpers/colour'
import { selectedBoard } from '../helpers/board'
Blockly.Blocks['sensebox_led'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_led)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsLED), "PIN")
.appendField(Blockly.Msg.senseBox_basic_state)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_on, "HIGH"], [Blockly.Msg.senseBox_off, "LOW"]]), "STAT");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_led_tip);
}
};
Blockly.Blocks['sensebox_rgb_led'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_rgb_led)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "PIN");
this.appendDummyInput()
.appendField(Blockly.Msg.COLOUR_RGB_RED)//Blockly.Msg.senseBox_basic_red
.appendField(new FieldSlider(255, 0, 255), "RED");
this.appendDummyInput()
.appendField(Blockly.Msg.COLOUR_RGB_GREEN)//Blockly.Msg.senseBox_basic_green
.appendField(new FieldSlider(255, 0, 255), "GREEN");
this.appendDummyInput()
.appendField(Blockly.Msg.COLOUR_RGB_BLUE)//Blockly.Msg.senseBox_basic_green
.appendField(new FieldSlider(255, 0, 255), "BLUE");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
@@ -0,0 +1,253 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
/*
----------------------------------LoRa--------------------------------------------------
*/
Blockly.Blocks['sensebox_lora_initialize_otaa'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_init_otaa_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField("Initialize LoRa (OTAA)");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_device_id)
.appendField(new Blockly.FieldTextInput("DEVICE ID"), "DEVICEID");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_app_id)
.appendField(new Blockly.FieldTextInput("APP ID"), "APPID");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_app_key)
.appendField(new Blockly.FieldTextInput("APP KEY"), "APPKEY");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_interval)
.appendField(new Blockly.FieldTextInput("5"), "INTERVAL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks['sensebox_lora_initialize_abp'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_init_abp_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField("Initialize LoRa (ABP)");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_nwskey_id)
.appendField(new Blockly.FieldTextInput("NWSKEY"), "NWSKEY");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_appskey_id)
.appendField(new Blockly.FieldTextInput("APPSKEY"), "APPSKEY");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_devaddr_id)
.appendField(new Blockly.FieldTextInput("DEVADDR"), "DEVADDR");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_interval)
.appendField(new Blockly.FieldTextInput("5"), "INTERVAL");
// this.appendStatementInput('DO')
// .appendField(Blockly.Msg.senseBox_measurements)
// .setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
};
Blockly.Blocks['sensebox_lora_message_send'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_message_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendStatementInput('DO')
.appendField(Blockly.Msg.senseBox_LoRa_send_message)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks['sensebox_send_lora_sensor_value'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_sensor_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_measurement)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("Bytes")
.appendField(new Blockly.FieldTextInput("2"), "MESSAGE_BYTES");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_lora_message_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_send'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendStatementInput('DO')
.appendField(Blockly.Msg.senseBox_LoRa_send_cayenne)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks['sensebox_lora_cayenne_temperature'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_temperature_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_temperature)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_humidity'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_humidity_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_humidity)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_pressure'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_pressure_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_pressure)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_luminosity'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_luminosity_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_luminosity)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_sensor'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_analog_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('Value')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_analog)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_accelerometer'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_gyros_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('X')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_x)
this.appendValueInput('Y')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_y)
this.appendValueInput('Z')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_z)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
Blockly.Blocks['sensebox_lora_cayenne_gps'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_LoRa_cayenne_gps_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendValueInput('LAT')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_lat)
this.appendValueInput('LNG')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_lng)
this.appendValueInput('ALT')
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_alt)
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_LoRa_cayenne_channel)
.appendField(new Blockly.FieldTextInput("1"), "CHANNEL");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ['sensebox_lora_cayenne_send'],
};
@@ -0,0 +1,112 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
Blockly.Blocks['sensebox_osem_connection'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_osem_connection_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_osem_connection)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_host, '"ingress.opensensemap.org"'], [Blockly.Msg.senseBox_osem_host_workshop, '"ingress.workshop.opensensemap.org"']]), "host")
.appendField('SSL')
.appendField(new Blockly.FieldCheckbox("TRUE"), "SSL");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_osem_exposure)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_stationary, 'Stationary'], [Blockly.Msg.senseBox_osem_mobile, 'Mobile']]), "type");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("senseBox ID")
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
this.appendStatementInput('DO')
.appendField(Blockly.Msg.senseBox_sensor)
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
onchange: function (e) {
//Blockly.Blocks.sensebox.getDescendants = blocks;
},
mutationToDom: function () {
var container = document.createElement('mutation');
var input = this.getFieldValue('type');
this.updateShape_(input);
container.setAttribute('type', input);
return container;
},
domToMutation: function (xmlElement) {
var connections = xmlElement.getAttribute('connections');
this.updateShape_(connections);
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var extraFieldExist = this.getFieldValue('gps');
var input = this.getFieldValue('type');
if ((input === 'Mobile') && extraFieldExist === null) {
this.appendValueInput('lat', 'Number')
.appendField(Blockly.Msg.senseBox_gps_lat, 'gps');
this.appendValueInput('lng', 'Number')
.appendField(Blockly.Msg.senseBox_gps_lng);
this.appendValueInput('altitude', 'Number')
.appendField(Blockly.Msg.senseBox_gps_alt);
this.appendValueInput('timeStamp', 'Number')
.appendField(Blockly.Msg.senseBox_gps_timeStamp);
}
if (input === 'Stationary' && extraFieldExist !== null) {
this.removeInput('lat');
this.removeInput('lng');
this.removeInput('altitude');
this.removeInput('timeStamp');
}
},
};
Blockly.Blocks['sensebox_send_to_osem'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_send_to_osem);
this.appendValueInput('Value')
.setCheck(null)
.appendField('Sensor ID')
.appendField(new Blockly.FieldTextInput('Sensor ID'), 'SensorID');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_osem_connection'],
};
@@ -0,0 +1,80 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
Blockly.Blocks['sensebox_sd_open_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_open_file)
.setAlign(Blockly.ALIGN_LEFT)
.appendField(
new Blockly.FieldTextInput('Data.txt'),
'Filename');
this.appendStatementInput('SD')
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
Blockly.Blocks['sensebox_sd_create_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_create_file)
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_output_filename)
.appendField(
new Blockly.FieldTextInput('Data.txt'),
'Filename');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
Blockly.Blocks['sensebox_sd_write_file'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sd_write_file)
.setAlign(Blockly.ALIGN_LEFT);
this.appendValueInput('DATA')
.setCheck(null);
this.appendDummyInput('CheckboxText')
.appendField(Blockly.Msg.senseBox_output_linebreak)
.appendField(new Blockly.FieldCheckbox('TRUE'), 'linebreak');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip);
this.setHelpUrl('https://sensebox.de/books');
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_sd_open_file'],
};
@@ -1,5 +1,12 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
import * as Types from '../helpers/types'
import { selectedBoard } from '../helpers/board'
/**
* HDC1080 Temperature and Humidity Sensor
*
*/
Blockly.Blocks['sensebox_sensor_temp_hum'] = {
init: function () {
@@ -9,12 +16,308 @@ Blockly.Blocks['sensebox_sensor_temp_hum'] = {
.setAlign(Blockly.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, "Number");
this.setColour(120);
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_temp_hum_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/temp_und_luftfeuchte.html');
}
};
/**
* VEML6070 and TSL4513
*
*/
Blockly.Blocks['sensebox_sensor_uv_light'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_uv_light);
this.appendDummyInput()
.setAlign(Blockly.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_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/temp_und_luftfeuchte.html');
}
};
/*
BMX055 Three differen Blocks for Accelerometer, Gyroscope, Compass
*/
Blockly.Blocks['sensebox_sensor_bmx055_accelerometer'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer_direction)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_bmx055_accelerometer_direction_x, "X"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_y, "Y"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_z, "Z"], [Blockly.Msg.senseBox_bmx055_accelerometer_direction_total, "Total"]]), "VALUE");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_bmx055_accelerometer_range)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_bmx055_accelerometer_range_2g, "0x3"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_4g, "0x5"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_8g, "0x8"], [Blockly.Msg.senseBox_bmx055_accelerometer_range_16g, "0x0C"]]), "RANGE");
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bmx055_accelerometer_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/temp_und_luftfeuchte.html');
}
};
/**
* SDS011 Fine Particular Matter Sensor
*
*/
Blockly.Blocks['sensebox_sensor_sds011'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sds011);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_sds011_pm25, "Pm25"], [Blockly.Msg.senseBox_sds011_pm10, "Pm10"]]), "NAME")
.appendField(Blockly.Msg.senseBox_sds011_dimension)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_sds011_serial1, "Serial1"], [Blockly.Msg.senseBox_sds011_serial2, "Serial2"]]), "SERIAL");
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sds011_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/temp_und_luftfeuchte.html');
}
};
/**
* BMP280 Pressure Sensor
*
*/
Blockly.Blocks['sensebox_sensor_pressure'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_pressure, "Pressure"], [Blockly.Msg.senseBox_temp, "Temperature"], [Blockly.Msg.senseBox_gps_alt, "Altitude"]];
var dropdown = new Blockly.FieldDropdown(dropdownOptions, function (option) {
var input = (option === 'Pressure') || (option === 'Temperature') || (option === 'Altitude');
this.sourceBlock_.updateShape_(input);
});
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_pressure_sensor);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(dropdown, "NAME");
this.setColour(getColour().sensebox);
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_pressure_tip);
this.setHelpUrl('https://edu.books.sensebox.de/de/projekte/diy_umweltstation/luftdruck.html');
},
getBlockType: function () {
return Blockly.Types.DECIMAL;
/**
* Parse XML to restore the number of pins available.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
(xmlElement.getAttribute('port'));
},
/**
* Create XML to represent number of pins selection.
* @return {!Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var input = this.getFieldValue('NAME');
this.updateShape_(input);
container.setAttribute('NAME', input);
return container;
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var extraFieldExist = this.getFieldValue('referencePressure');
var input = this.getFieldValue('NAME');
if (input === 'Altitude' && extraFieldExist === null) {
this.appendDummyInput('extraField')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_pressure_referencePressure)
.appendField(new Blockly.FieldTextInput("1013"), "referencePressure")
.appendField(Blockly.Msg.senseBox_pressure_referencePressure_dim);
}
if ((input === 'Pressure' || input === 'Temperature') && extraFieldExist !== null) {
this.removeInput('extraField');
}
}
};
/**
* BME680 Environmental Sensor
*
*/
Blockly.Blocks['sensebox_sensor_bme680_bsec'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"], [Blockly.Msg.senseBox_pressure, "pressure"], [Blockly.Msg.senseBox_bme_iaq, "IAQ"], [Blockly.Msg.senseBox_bme_iaq_accuracy, "IAQAccuracy"], [Blockly.Msg.senseBox_bme_co2, "CO2"], [Blockly.Msg.senseBox_bme_breatheVocEquivalent, "breathVocEquivalent"]];
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_bme680);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bme_tip);
}
};
/**
* Ultrasonic Sensor
*
*
*/
Blockly.Blocks['sensebox_sensor_ultrasonic_ranger'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, 'A'],
[Blockly.Msg.senseBox_ultrasonic_port_B, 'B'], [Blockly.Msg.senseBox_ultrasonic_port_C, 'C']];
var dropdown = new Blockly.FieldDropdown(dropdownOptions, function (option) {
var input = (option === 'A') || (option === 'B') || (option === 'C');
this.sourceBlock_.updateShape_(input);
});
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_ultrasonic)
.appendField(dropdown, "port");
this.appendDummyInput('TrigEcho')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_ultrasonic_trigger)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'ultrasonic_trigger')
.appendField(Blockly.Msg.senseBox_ultrasonic_echo)
.appendField(new Blockly.FieldDropdown(
selectedBoard().digitalPins), 'ultrasonic_echo');
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_ultrasonic_tip);
this.setHelpUrl('https://sensebox.de/books');
},
/**
* Parse XML to restore the number of pins available.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function (xmlElement) {
(xmlElement.getAttribute('port'));
},
/**
* Create XML to represent number of pins selection.
* @return {!Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function () {
var container = document.createElement('mutation');
var input = this.getFieldValue('port');
this.updateShape_(input);
container.setAttribute("port", input);
return container;
},
/**
* Modify this block to have the correct number of pins available.
* @param {boolean}
* @private
* @this Blockly.Block
*/
updateShape_: function () {
var input = this.getFieldValue('port');
switch (input) {
case 'A':
this.setFieldValue('1', 'ultrasonic_trigger');
this.setFieldValue('2', 'ultrasonic_echo');
break;
case 'B':
this.setFieldValue('3', 'ultrasonic_trigger');
this.setFieldValue('4', 'ultrasonic_echo');
break;
case 'C':
this.setFieldValue('5', 'ultrasonic_trigger');
this.setFieldValue('6', 'ultrasonic_echo');
break;
default:
break;
}
}
};
/**
* Microphone
*
*/
Blockly.Blocks['sensebox_sensor_sound'] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_sound)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().analogPins), "PIN")
this.setOutput(true, Types.NUMBER.typeName);
this.setHelpUrl(Blockly.Msg.senseBox_sound_tip);
this.setTooltip('Dieser Sensor mist den Geräuschpegel.');
}
};
/**
* Button
*
*
*/
Blockly.Blocks['sensebox_button'] = {
init: function () {
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_button)
.appendField(new Blockly.FieldDropdown([[Blockly.Msg.senseBox_button_isPressed, "isPressed"], [Blockly.Msg.senseBox_button_wasPressed, "wasPressed"], [Blockly.Msg.senseBox_button_switch, "Switch"]]), "FUNCTION")
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsButton), "PIN");
this.setOutput(true, Types.BOOLEAN.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_button_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};
/**
* SCD30 CO2 Sensor
*
*/
Blockly.Blocks['sensebox_scd30'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_temp, "temperature"], [Blockly.Msg.senseBox_hum, "humidity"], [Blockly.Msg.senseBox_bme_co2, "CO2"]];
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_scd30);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.senseBox_value)
.appendField(new Blockly.FieldDropdown(dropdownOptions), "dropdown")
this.setOutput(true, Types.NUMBER.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bme_tip);
}
};
@@ -0,0 +1,53 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
Blockly.Blocks["sensebox_telegram"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_telegram_init);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("telegram")
.appendField(new Blockly.FieldTextInput("token"), "telegram_token");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks["sensebox_telegram_do"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_do);
this.appendStatementInput("telegram_do");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks["sensebox_telegram_do_on_message"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_do_on_message);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_telegram_message)
.appendField(new Blockly.FieldTextInput("/message"), 'telegram_message');
this.appendStatementInput("telegram_do_on_message").setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
Blockly.Blocks["sensebox_telegram_send"] = {
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_telegram_send);
this.appendValueInput("telegram_text_to_send").setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
LOOP_TYPES: ["sensebox_telegram_do_on_message"]
};
@@ -0,0 +1,58 @@
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
Blockly.Blocks['sensebox_wifi'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_wifi_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_wifi_connect);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_wifi_ssid)
.appendField(new Blockly.FieldTextInput("SSID"), "SSID");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_output_password)
.appendField(new Blockly.FieldTextInput("Password"), "Password");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) !== -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['arduino_functions'],
};
Blockly.Blocks['sensebox_startap'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_wifi_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_wifi_startap);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_wifi_ssid)
.appendField(new Blockly.FieldTextInput("SSID"), "SSID");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
+2 -14
View File
@@ -1,16 +1,4 @@
import Blockly from 'blockly';
Blockly.Blocks["sensebox_telegram"] = {
init: function () {
this.setColour(120);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_telegram_init);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField("telegram")
.appendField(new Blockly.FieldTextInput("token"), "telegram_token");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
+202
View File
@@ -0,0 +1,202 @@
import Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import * as Types from '../helpers/types';
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
// Block for text value
{
"type": "text",
"message0": "%1",
"args0": [{
"type": "field_input",
"name": "TEXT",
"text": ""
}],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
"extensions": [
"text_quotes",
"parent_tooltip_when_inline"
]
},
{
"type": "text_multiline",
"message0": "%1 %2",
"args0": [{
"type": "field_image",
"src": 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAARCAYAAADpP' +
'U2iAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAdhgAAHYYBXaITgQAAABh0RVh0' +
'U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAP1JREFUOE+Vks0KQUEYhjm' +
'RIja4ABtZ2dm5A3t3Ia6AUm7CylYuQRaUhZSlLZJiQbFAyRnPN33y01HOW08z88' +
'73zpwzM4F3GWOCruvGIE4/rLaV+Nq1hVGMBqzhqlxgCys4wJA65xnogMHsQ5luj' +
'nYHTejBBCK2mE4abjCgMGhNxHgDFWjDSG07kdfVa2pZMf4ZyMAdWmpZMfYOsLiD' +
'MYMjlMB+K613QISRhTnITnsYg5yUd0DETmEoMlkFOeIT/A58iyK5E18BuTBfgYX' +
'fwNJv4P9/oEBerLylOnRhygmGdPpTTBZAPkde61lbQe4moWUvYUZYLfUNftIY4z' +
'wA5X2Z9AYnQrEAAAAASUVORK5CYII=',
"width": 12,
"height": 17,
"alt": '\u00B6'
}, {
"type": "field_multilinetext",
"name": "TEXT",
"text": ""
}],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
"extensions": [
"parent_tooltip_when_inline"
]
},
{
"type": "text_join",
"message0": "",
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_JOIN_HELPURL}",
"tooltip": "%{BKY_TEXT_JOIN_TOOLTIP}",
"mutator": "text_join_mutator"
},
{
"type": "text_create_join_container",
"message0": "%{BKY_TEXT_CREATE_JOIN_TITLE_JOIN} %1 %2",
"args0": [{
"type": "input_dummy"
},
{
"type": "input_statement",
"name": "STACK"
}],
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_CREATE_JOIN_TOOLTIP}",
"enableContextMenu": false
},
{
"type": "text_create_join_item",
"message0": "%{BKY_TEXT_CREATE_JOIN_ITEM_TITLE_ITEM}",
"previousStatement": null,
"nextStatement": null,
"style": getColour().text,
"tooltip": "%{BKY_TEXT_CREATE_JOIN_ITEM_TOOLTIP}",
"enableContextMenu": false
},
{
"type": "text_append",
"message0": "%{BKY_TEXT_APPEND_TITLE}",
"args0": [{
"type": "field_variable",
"name": "VAR",
"variable": "%{BKY_TEXT_APPEND_VARIABLE}"
},
{
"type": "input_value",
"name": "TEXT"
}],
"previousStatement": null,
"nextStatement": null,
"style": "text_blocks",
"extensions": [
"text_append_tooltip"
]
},
{
"type": "text_length",
"message0": "%{BKY_TEXT_LENGTH_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": ['String', 'Array']
}
],
"output": Types.NUMBER.typeName,
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_LENGTH_TOOLTIP}",
"helpUrl": "%{BKY_TEXT_LENGTH_HELPURL}"
},
{
"type": "text_isEmpty",
"message0": "%{BKY_TEXT_ISEMPTY_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": ['String', 'Array']
}
],
"output": Types.BOOLEAN.typeName,
"style": "text_blocks",
"tooltip": "%{BKY_TEXT_ISEMPTY_TOOLTIP}",
"helpUrl": "%{BKY_TEXT_ISEMPTY_HELPURL}"
},
{
"type": "text_indexOf",
"message0": "%{BKY_TEXT_INDEXOF_TITLE}",
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "String"
},
{
"type": "field_dropdown",
"name": "END",
"options": [
[
"%{BKY_TEXT_INDEXOF_OPERATOR_FIRST}",
"FIRST"
],
[
"%{BKY_TEXT_INDEXOF_OPERATOR_LAST}",
"LAST"
]
]
},
{
"type": "input_value",
"name": "FIND",
"check": "String"
}
],
"output": Types.NUMBER.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_INDEXOF_HELPURL}",
"inputsInline": true,
"extensions": [
"text_indexOf_tooltip"
]
},
{
"type": "text_charAt",
"message0": "%{BKY_TEXT_CHARAT_TITLE}", // "in text %1 %2"
"args0": [
{
"type": "input_value",
"name": "VALUE",
"check": "String"
},
{
"type": "field_dropdown",
"name": "WHERE",
"options": [
["%{BKY_TEXT_CHARAT_FROM_START}", "FROM_START"],
["%{BKY_TEXT_CHARAT_FROM_END}", "FROM_END"],
["%{BKY_TEXT_CHARAT_FIRST}", "FIRST"],
["%{BKY_TEXT_CHARAT_LAST}", "LAST"],
["%{BKY_TEXT_CHARAT_RANDOM}", "RANDOM"]
]
}
],
"output": Types.TEXT.typeName,
"style": "text_blocks",
"helpUrl": "%{BKY_TEXT_CHARAT_HELPURL}",
"inputsInline": true,
"mutator": "text_charAt_mutator"
}
]); // END JSON EXTRACT (Do not delete this comment.)
+130
View File
@@ -0,0 +1,130 @@
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Blocks for Arduino Time functions.
* The arduino built in functions syntax can be found in
* http://arduino.cc/en/Reference/HomePage
*/
import Blockly from 'blockly';
import { getColour } from '../helpers/colour'
import * as Types from '../helpers/types'
Blockly.Blocks['time_delay'] = {
/**
* Delay block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Delay');
this.setColour(getColour().time);
this.appendValueInput('DELAY_TIME_MILI')
.setCheck(Types.NUMBER.checkList)
.appendField(Blockly.Msg.ARD_TIME_DELAY);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MS);
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP);
}
};
Blockly.Blocks['time_delaymicros'] = {
/**
* delayMicroseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/DelayMicroseconds');
this.setColour(getColour().time);
this.appendValueInput('DELAY_TIME_MICRO')
.setCheck(Types.NUMBER.checkList)
.appendField(Blockly.Msg.ARD_TIME_DELAY);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_DELAY_MICROS);
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_MICRO_TIP);
}
};
Blockly.Blocks['time_millis'] = {
/**
* Elapsed time in milliseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MILLIS);
this.setOutput(true, Types.LARGE_NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
},
/** @return {string} The type of return value for the block, an integer. */
getBlockType: function () {
return Blockly.Types.LARGE_NUMBER;
}
};
Blockly.Blocks['time_micros'] = {
/**
* Elapsed time in microseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Micros');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_MICROS);
this.setOutput(true, Types.LARGE_NUMBER.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MICROS_TIP);
},
/**
* Should be a long (32bit), but for for now an int.
* @return {string} The type of return value for the block, an integer.
*/
getBlockType: function () {
return Types.LARGE_NUMBER;
}
};
Blockly.Blocks['infinite_loop'] = {
/**
* Waits forever, end of program.
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.ARD_TIME_INF);
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setTooltip(Blockly.Msg.ARD_TIME_INF_TIP);
}
};
Blockly.Blocks['sensebox_interval_timer'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_interval_timer_tip);
this.setInputsInline(true);
this.setHelpUrl('');
this.setColour(getColour().time);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_interval_timer);
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(new Blockly.FieldTextInput("10000"), "interval")
.appendField(Blockly.Msg.senseBox_interval);
this.appendStatementInput('DO')
.setCheck(null);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
@@ -0,0 +1,43 @@
import Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
import { getCompatibleTypes } from '../helpers/types'
Blockly.Blocks['variables_set_dynamic'] = {
init: function () {
// const type = myVar.type;
this.setColour(getColour().variables);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.appendValueInput('VALUE')
.appendField('set', 'set')
.appendField('', 'type')
.appendField(new Blockly.FieldVariable('VAR'), 'VAR')
.appendField('to');
},
onchange: function (e) {
let variableID = this.getFieldValue('VAR');
let variable = Blockly.getMainWorkspace().getVariableMap().getVariableById(variableID)
this.getField('type').setValue(variable.type);
this.getInput('VALUE').setCheck(getCompatibleTypes(variable.type));
}
}
Blockly.Blocks['variables_get_dynamic'] = {
init: function () {
this.setColour(getColour().variables);
this.appendDummyInput()
.appendField('', 'type')
.appendField(new Blockly.FieldVariable('VAR'), 'VAR');
this.setOutput(true);
},
onchange: function (e) {
let variableID = this.getFieldValue('VAR');
let variable = Blockly.getMainWorkspace().getVariableMap().getVariableById(variableID)
this.getField('type').setValue(variable.type);
}
}
+25
View File
@@ -0,0 +1,25 @@
import * as Blockly from 'blockly/core';
/**
* Function for turning the tone library on on a given pin (X).
* Arduino code: setup { pinMode(X, OUTPUT) }
* loop { tone(X, frequency) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['io_tone'] = function (block) {
var pin = block.getFieldValue('TONEPIN');
var freq = Blockly.Arduino.valueToCode(block, 'FREQUENCY', Blockly.Arduino.ORDER_ATOMIC);
Blockly.Arduino.setupCode_['io_tone' + pin] = 'pinMode(' + pin + ', OUTPUT);\n';
var code = 'tone(' + pin + ',' + freq + ');\n';
return code;
};
Blockly.Arduino['io_notone'] = function (block) {
var pin = block.getFieldValue("TONEPIN");
Blockly.Arduino.setupCode_['io_tone' + pin] = 'pinMode(' + pin + ', OUTPUT);\n';
var code = 'noTone(' + pin + ');\n';
return code;
};
+54 -16
View File
@@ -25,7 +25,6 @@
// https://developers.google.com/blockly/guides/create-custom-blocks/generating-code
import * as Blockly from 'blockly/core';
import * as _ from 'lodash';
/**
* Arduino code generator.
@@ -81,6 +80,19 @@ Blockly['Arduino'].ORDER_ASSIGNMENT = 14; // = *= /= ~/= %= += -= <<= >>= &= ^=
Blockly['Arduino'].ORDER_COMMA = 18; // ,
Blockly['Arduino'].ORDER_NONE = 99; // (...)
/**
*
* @param {} workspace
*
* Blockly Types
*/
/**
* Initialise the database of variable names.
* @param {!Blockly.Workspace} workspace Workspace to generate code from.
@@ -89,9 +101,20 @@ Blockly['Arduino'].init = function (workspace) {
// Create a dictionary of definitions to be printed before the code.
Blockly['Arduino'].libraries_ = Object.create(null);
Blockly['Arduino'].definitions_ = Object.create(null);
// creates a list of code to be setup before the setup block
Blockly['Arduino'].setupCode_ = Object.create(null);
// creates a list of code for the loop to be runned once
Blockly['Arduino'].loopCodeOnce_ = Object.create(null)
// creates a list of code for the loop to be runned once
Blockly['Arduino'].codeFunctions_ = Object.create(null)
// creates a list of code variables
Blockly['Arduino'].variables_ = Object.create(null)
// Create a dictionary mapping desired function names in definitions_
// to actual function names (to avoid collisions with user functions).
Blockly['Arduino'].functionNames_ = Object.create(null);
@@ -172,39 +195,47 @@ Blockly['Arduino'].init = function (workspace) {
*/
Blockly['Arduino'].finish = function (code) {
let libraryCode = '';
let variablesCode = '';
let codeFunctions = '';
let functionsCode = '';
let definitionsCode = '';
let loopCodeOnce = '';
let setupCode = '';
let preSetupCode = '';
let devVariables = '\n';
for (const key in Blockly['Arduino'].libraries_) {
libraryCode += Blockly['Arduino'].libraries_[key] + '\n';
}
for (const key in Blockly['Arduino'].variables_) {
variablesCode += Blockly['Arduino'].variables_[key] + '\n';
}
for (const key in Blockly['Arduino'].definitions_) {
definitionsCode += Blockly['Arduino'].definitions_[key] + '\n';
}
for (const key in Blockly['Arduino'].loopCodeOnce_) {
loopCodeOnce += Blockly['Arduino'].loopCodeOnce_[key] + '\n';
}
for (const key in Blockly['Arduino'].codeFunctions_) {
codeFunctions += Blockly['Arduino'].codeFunctions_[key] + '\n';
}
for (const key in Blockly['Arduino'].functionNames_) {
functionsCode += Blockly['Arduino'].functionNames_[key] + '\n';
}
if (!_.isEmpty(Blockly['Arduino'].setupCode_['bluetooth_setup'])) {
devVariables += 'String bluetoothMessageDEV = ""; \n';
}
if (!_.isEmpty(Blockly['Arduino'].setupCode_['serial_begin'])) {
devVariables += 'String serialMessageDEV = ""; \n';
}
if (!_.isEmpty(Blockly['Arduino'].functionNames_['double_to_string_debug'])) {
devVariables += 'boolean stopDebugging = false; \n';
}
let setupCode = '';
let preSetupCode = '';
for (const key in Blockly['Arduino'].setupCode_) {
preSetupCode += Blockly['Arduino'].setupCode_[key] || '';
}
setupCode = '\nvoid setup() { \n' + preSetupCode + '\n}\n';
let loopCode = '\nvoid loop() { \n' + code + '\n}\n';
let loopCode = '\nvoid loop() { \n' + loopCodeOnce + code + '\n}\n';
// Convert the definitions dictionary into a list.
@@ -213,6 +244,12 @@ Blockly['Arduino'].finish = function (code) {
'\n' +
libraryCode +
'\n' +
variablesCode +
'\n' +
definitionsCode +
'\n' +
codeFunctions +
'\n' +
Blockly['Arduino'].variablesInitCode_ +
'\n' +
functionsCode +
@@ -225,6 +262,7 @@ Blockly['Arduino'].finish = function (code) {
// Clean up temporary data.
delete Blockly['Arduino'].definitions_;
delete Blockly['Arduino'].functionNames_;
delete Blockly['Arduino'].loopCodeOnce_;
delete Blockly['Arduino'].variablesInitCode_;
delete Blockly['Arduino'].libraries_;
Blockly['Arduino'].variableDB_.reset();
+17 -1
View File
@@ -1,5 +1,21 @@
import './generator';
import './loops';
import './sensebox';
import './sensebox-sensors';
import './sensebox-telegram';
import './sensebox-osem';
import './sensebox-web';
import './sensebox-display';
import './sensebox-lora';
import './sensebox-led';
import './sensebox-sd';
import './logic';
import './text';
import './math';
import './map';
import './io';
import './audio';
import './procedures';
import './time';
import './variables';
+114
View File
@@ -0,0 +1,114 @@
import * as Blockly from 'blockly/core';
/**
* Function for 'set pin' (X) to a state (Y).
* Arduino code: setup { pinMode(X, OUTPUT); }
* loop { digitalWrite(X, Y); }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['io_digitalwrite'] = function (block) {
var pin = block.getFieldValue('PIN');
var stateOutput = Blockly.Arduino.valueToCode(
block, 'STATE', Blockly['Arduino'].ORDER_ATOMIC) || 'LOW';
Blockly['Arduino'].setupCode_['pinMode'] = 'pinMode(' + pin + ', OUTPUT);';
var code = 'digitalWrite(' + pin + ', ' + stateOutput + ');\n';
return code;
};
/**
* Function for reading a digital pin (X).
* Arduino code: setup { pinMode(X, INPUT); }
* loop { digitalRead(X) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['io_digitalread'] = function (block) {
var pin = block.getFieldValue('PIN');
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pinMode(' + pin + ', INPUT);'
var code = 'digitalRead(' + pin + ')';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Function for setting the state (Y) of a built-in LED (X).
* Arduino code: setup { pinMode(X, OUTPUT); }
* loop { digitalWrite(X, Y); }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['io_builtin_led'] = function (block) {
var pin = block.getFieldValue('BUILT_IN_LED');
var stateOutput = Blockly.Arduino.valueToCode(
block, 'STATE', Blockly.Arduino.ORDER_ATOMIC) || 'LOW';
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pindMode(' + pin + 'OUTPUT);'
var code = 'digitalWrite(' + pin + ', ' + stateOutput + ');\n';
return code;
};
/**
* Function for setting the state (Y) of an analogue output (X).
* Arduino code: setup { pinMode(X, OUTPUT); }
* loop { analogWrite(X, Y); }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['io_analogwrite'] = function (block) {
var pin = block.getFieldValue('PIN');
var stateOutput = Blockly.Arduino.valueToCode(
block, 'NUM', Blockly.Arduino.ORDER_ATOMIC) || '0';
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pinMode(' + pin + ', OUTPUT);';
// Warn if the input value is out of range
if ((stateOutput < 0) || (stateOutput > 255)) {
block.setWarningText('The analogue value set must be between 0 and 255',
'pwm_value');
} else {
block.setWarningText(null, 'pwm_value');
}
var code = 'analogWrite(' + pin + ', ' + stateOutput + ');\n';
return code;
};
/**
* Function for reading an analogue pin value (X).
* Arduino code: setup { pinMode(X, INPUT); }
* loop { analogRead(X) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['io_analogread'] = function (block) {
var pin = block.getFieldValue('PIN');
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pinMode(' + pin + ', INPUT);';
var code = 'analogRead(' + pin + ')';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Value for defining a digital pin state.
* Arduino code: loop { HIGH / LOW }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['io_highlow'] = function (block) {
var code = block.getFieldValue('STATE');
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
Blockly.Arduino['io_pulsein'] = function (block) {
var pin = block.getFieldValue("PULSEPIN");
var type = Blockly.Arduino.valueToCode(block, "PULSETYPE", Blockly.Arduino.ORDER_ATOMIC);
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pinMode(' + pin + ', INPUT);';
var code = 'pulseIn(' + pin + ', ' + type + ')';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
Blockly.Arduino['io_pulsetimeout'] = function (block) {
var pin = block.getFieldValue("PULSEPIN");
var type = Blockly.Arduino.valueToCode(block, "PULSETYPE", Blockly.Arduino.ORDER_ATOMIC);
var timeout = Blockly.Arduino.valueToCode(block, "TIMEOUT", Blockly.Arduino.ORDER_ATOMIC);
Blockly['Arduino'].setupCode_['pinMode' + pin] = 'pinMode(' + pin + ', INPUT);';
var code = 'pulseIn(' + pin + ', ' + type + ', ' + timeout + ')';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
+59 -3
View File
@@ -1,5 +1,4 @@
import * as Blockly from 'blockly/core';
import { Block } from 'blockly';
Blockly.Arduino['logic_boolean'] = function (Block) {
// Boolean values true and false.
@@ -55,7 +54,7 @@ Blockly.Arduino['logic_operation'] = function (Block) {
return [code, order];
};
Blockly.Arduino['control_if'] = function (Block) {
Blockly.Arduino['controls_if'] = function (Block) {
// If/elseif/else condition.
let n = 0;
let code = '',
@@ -87,7 +86,37 @@ Blockly.Arduino['control_if'] = function (Block) {
return code + '\n';
};
Blockly.Arduino['controls_ifelse'] = Blockly.Arduino['control_if'];
Blockly.Arduino['controls_ifelse'] = function (Block) {
// If/elseif/else condition.
let n = 0;
let code = '',
branchCode,
conditionCode;
do {
conditionCode =
Blockly.Arduino.valueToCode(
Block,
'IF' + n,
Blockly.Arduino.ORDER_NONE
) || 'false';
branchCode = Blockly.Arduino.statementToCode(Block, 'DO' + n);
code +=
(n > 0 ? ' else ' : '') +
'if (' +
conditionCode +
') {\n' +
branchCode +
'}';
++n;
} while (Block.getInput('IF' + n));
if (Block.getInput('ELSE')) {
branchCode = Blockly.Arduino.statementToCode(Block, 'ELSE');
code += ' else {\n' + branchCode + '}';
}
return code + '\n';
}
Blockly.Arduino['logic_negate'] = function (Block) {
// Negation.
@@ -96,3 +125,30 @@ Blockly.Arduino['logic_negate'] = function (Block) {
const code = '!' + argument0;
return [code, order];
};
Blockly.Arduino['switch_case'] = function (block) {
var n = 0;
var argument = Blockly.Arduino.valueToCode(this, 'CONDITION',
Blockly.Arduino.ORDER_NONE) || '';
var branch = Blockly.Arduino.statementToCode(block, 'CASECONDITON0' + n);
var cases = '';
var default_code = '';
var DO = Blockly.Arduino.statementToCode(block, ('CASE' + n));
for (n = 0; n <= block.caseCount_; n++) {
DO = Blockly.Arduino.statementToCode(block, ('CASE' + n));
branch = Blockly.Arduino.valueToCode(block, ('CASECONDITION' + n), Blockly.Arduino.ORDER_NONE) || '0';
cases += 'case ' + branch + ':\n';
cases += DO + '\nbreak;\n';
}
if (block.defaultCount_) {
branch = Blockly.Arduino.statementToCode(block, 'ONDEFAULT');
default_code = 'default: \n' + branch + '\n break;\n';
}
var code = 'switch (' + argument + ') {\n' + cases + default_code + '}';
return code + '\n';
};
+7 -3
View File
@@ -1,5 +1,5 @@
import * as Blockly from 'blockly/core';
import { Block } from 'blockly';
Blockly['Arduino']['controls_repeat_ext'] = function (Block) {
// Repeat n times.
@@ -14,9 +14,9 @@ Blockly['Arduino']['controls_repeat_ext'] = function (Block) {
let branch = Blockly['Arduino'].statementToCode(Block, 'DO');
branch = Blockly['Arduino'].addLoopTrap(branch, Block.id);
let code = '';
const loopVar = 'simple_loop_variable';
const loopVar = 'i';
code +=
'for (' +
'for (int ' +
loopVar +
' = 1; ' +
loopVar +
@@ -36,6 +36,8 @@ Blockly['Arduino']['controls_for'] = function (Block) {
Block.getFieldValue('VAR')
).name;
const branch = Blockly['Arduino'].statementToCode(Block, 'DO');
const startNumber =
@@ -111,6 +113,8 @@ Blockly['Arduino']['controls_flow_statements'] = function (Block) {
return 'break;\n';
case 'CONTINUE':
return 'continue;\n';
default:
break;
}
throw Error('Unknown flow statement.');
};
+24
View File
@@ -0,0 +1,24 @@
import * as Blockly from 'blockly/core';
/**
* Code generator for the map block.
* Arduino code: loop { map(x, 0, 1024, 0, y) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['base_map'] = function (block) {
var valueNum = Blockly.Arduino.valueToCode(
block, 'NUM', Blockly.Arduino.ORDER_NONE) || '0';
var fromMin = Blockly.Arduino.valueToCode(
block, 'FMIN', Blockly.Arduino.ORDER_ATOMIC) || '0';
var fromMax = Blockly.Arduino.valueToCode(
block, 'FMAX', Blockly.Arduino.ORDER_ATOMIC) || '0';
var valueDmin = Blockly.Arduino.valueToCode(
block, 'DMIN', Blockly.Arduino.ORDER_ATOMIC) || '0';
var valueDmax = Blockly.Arduino.valueToCode(
block, 'DMAX', Blockly.Arduino.ORDER_ATOMIC) || '0';
var code = 'map(' + valueNum + ',' + fromMin + ',' + fromMax + ',' + valueDmin + ',' + valueDmax + ')';
return [code, Blockly.Arduino.ORDER_NONE];
};
+347
View File
@@ -0,0 +1,347 @@
import * as Blockly from 'blockly/core';
/**
* @license Licensed under the Apache License, Version 2.0 (the "License"):
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* @fileoverview Generating Arduino code for the Math blocks.
*
* TODO: Math on list needs lists to be implemented.
* math_constant and math_change needs to be tested in compiler.
*/
/**
* Generator for a numeric value (X).
* Arduino code: loop { X }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_number'] = function (block) {
// Numeric value.
var code = parseFloat(block.getFieldValue('NUM'));
if (code === Infinity) {
code = 'INFINITY';
} else if (code === -Infinity) {
code = '-INFINITY';
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Generator for a basic arithmetic operators (X and Y) and power function
* (X ^ Y).
* Arduino code: loop { X operator Y }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_arithmetic'] = function (block) {
var OPERATORS = {
ADD: [' + ', Blockly.Arduino.ORDER_ADDITIVE],
MINUS: [' - ', Blockly.Arduino.ORDER_ADDITIVE],
MULTIPLY: [' * ', Blockly.Arduino.ORDER_MULTIPLICATIVE],
DIVIDE: [' / ', Blockly.Arduino.ORDER_MULTIPLICATIVE],
POWER: [null, Blockly.Arduino.ORDER_NONE] // Handle power separately.
};
var tuple = OPERATORS[block.getFieldValue('OP')];
var operator = tuple[0];
var order = tuple[1];
var argument0 = Blockly.Arduino.valueToCode(block, 'A', order) || '0';
var argument1 = Blockly.Arduino.valueToCode(block, 'B', order) || '0';
var code;
// Power in C++ requires a special case since it has no operator.
if (!operator) {
code = 'Math.pow(' + argument0 + ', ' + argument1 + ')';
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
}
code = argument0 + operator + argument1;
return [code, order];
};
/**
* Generator for math operators that contain a single operand (X).
* Arduino code: loop { operator(X) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_single'] = function (block) {
var operator = block.getFieldValue('OP');
var code;
var arg;
if (operator === 'NEG') {
// Negation is a special case given its different operator precedents.
arg = Blockly.Arduino.valueToCode(block, 'NUM',
Blockly.Arduino.ORDER_UNARY_PREFIX) || '0';
if (arg[0] === '-') {
// --3 is not legal in C++ in this context.
arg = ' ' + arg;
}
code = '-' + arg;
return [code, Blockly.Arduino.ORDER_UNARY_PREFIX];
}
if (operator === 'ABS' || operator.substring(0, 5) === 'ROUND') {
arg = Blockly.Arduino.valueToCode(block, 'NUM',
Blockly.Arduino.ORDER_UNARY_POSTFIX) || '0';
} else if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') {
arg = Blockly.Arduino.valueToCode(block, 'NUM',
Blockly.Arduino.ORDER_MULTIPLICATIVE) || '0';
} else {
arg = Blockly.Arduino.valueToCode(block, 'NUM',
Blockly.Arduino.ORDER_NONE) || '0';
}
// First, handle cases which generate values that don't need parentheses.
switch (operator) {
case 'ABS':
code = 'abs(' + arg + ')';
break;
case 'ROOT':
code = 'sqrt(' + arg + ')';
break;
case 'LN':
code = 'log(' + arg + ')';
break;
case 'EXP':
code = 'exp(' + arg + ')';
break;
case 'POW10':
code = 'pow(10,' + arg + ')';
break;
case 'ROUND':
code = 'round(' + arg + ')';
break;
case 'ROUNDUP':
code = 'ceil(' + arg + ')';
break;
case 'ROUNDDOWN':
code = 'floor(' + arg + ')';
break;
case 'SIN':
code = 'sin(' + arg + ' / 180 * Math.PI)';
break;
case 'COS':
code = 'cos(' + arg + ' / 180 * Math.PI)';
break;
case 'TAN':
code = 'tan(' + arg + ' / 180 * Math.PI)';
break;
default:
break;
}
if (code) {
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
}
// Second, handle cases which generate values that may need parentheses.
switch (operator) {
case 'LOG10':
code = 'log(' + arg + ') / log(10)';
break;
case 'ASIN':
code = 'asin(' + arg + ') / M_PI * 180';
break;
case 'ACOS':
code = 'acos(' + arg + ') / M_PI * 180';
break;
case 'ATAN':
code = 'atan(' + arg + ') / M_PI * 180';
break;
default:
throw new Error('Unknown math operator: ' + operator);
}
return [code, Blockly.Arduino.ORDER_MULTIPLICATIVE];
};
/**
* Generator for math constants (PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2),
* INFINITY).
* Arduino code: loop { constant }
* TODO: Might need to include "#define _USE_MATH_DEFINES"
* The arduino header file already includes math.h
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['math_constant'] = function (block) {
var CONSTANTS = {
'PI': ['M_PI', Blockly.Arduino.ORDER_UNARY_POSTFIX],
'E': ['M_E', Blockly.Arduino.ORDER_UNARY_POSTFIX],
'GOLDEN_RATIO': ['(1 + sqrt(5)) / 2', Blockly.Arduino.ORDER_MULTIPLICATIVE],
'SQRT2': ['M_SQRT2', Blockly.Arduino.ORDER_UNARY_POSTFIX],
'SQRT1_2': ['M_SQRT1_2', Blockly.Arduino.ORDER_UNARY_POSTFIX],
'INFINITY': ['INFINITY', Blockly.Arduino.ORDER_ATOMIC]
};
return CONSTANTS[block.getFieldValue('CONSTANT')];
};
/**
* Generator for math checks: if a number is even, odd, prime, whole, positive,
* negative, or if it is divisible by certain number. Returns true or false.
* Arduino code: complex code, can create external functions.
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_number_property'] = function (block) {
var number_to_check = Blockly.Arduino.valueToCode(block, 'NUMBER_TO_CHECK',
Blockly.Arduino.ORDER_MULTIPLICATIVE) || '0';
var dropdown_property = block.getFieldValue('PROPERTY');
var code;
if (dropdown_property === 'PRIME') {
var func = [
'boolean ' + Blockly.Arduino.DEF_FUNC_NAME + '(int n) {',
' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
' if (n == 2 || n == 3) {',
' return true;',
' }',
' // False if n is NaN, negative, is 1.',
' // And false if n is divisible by 2 or 3.',
' if (isnan(n) || (n <= 1) || (n == 1) || (n % 2 == 0) || ' +
'(n % 3 == 0)) {',
' return false;',
' }',
' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
' for (int x = 6; x <= sqrt(n) + 1; x += 6) {',
' if (n % (x - 1) == 0 || n % (x + 1) == 0) {',
' return false;',
' }',
' }',
' return true;',
'}'];
var funcName = Blockly.Arduino.addFunction('mathIsPrime', func.join('\n'));
Blockly.Arduino.addInclude('math', '#include <math.h>');
code = funcName + '(' + number_to_check + ')';
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
}
switch (dropdown_property) {
case 'EVEN':
code = number_to_check + ' % 2 == 0';
break;
case 'ODD':
code = number_to_check + ' % 2 == 1';
break;
case 'WHOLE':
Blockly.Arduino.addInclude('math', '#include <math.h>');
code = '(floor(' + number_to_check + ') == ' + number_to_check + ')';
break;
case 'POSITIVE':
code = number_to_check + ' > 0';
break;
case 'NEGATIVE':
code = number_to_check + ' < 0';
break;
case 'DIVISIBLE_BY':
var divisor = Blockly.Arduino.valueToCode(block, 'DIVISOR',
Blockly.Arduino.ORDER_MULTIPLICATIVE) || '0';
code = number_to_check + ' % ' + divisor + ' == 0';
break;
default:
break;
}
return [code, Blockly.Arduino.ORDER_EQUALITY];
};
/**
* Generator to add (Y) to a variable (X).
* If variable X has not been declared before this block it will be declared as
* a (not initialised) global int, however globals are 0 initialised in C/C++.
* Arduino code: loop { X += Y; }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_change'] = function (block) {
var argument0 = Blockly.Arduino.valueToCode(block, 'DELTA',
Blockly.Arduino.ORDER_ADDITIVE) || '0';
var varName = Blockly.Arduino.variableDB_.getName(
block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
return varName + ' += ' + argument0 + ';\n';
};
/** Rounding functions have a single operand. */
Blockly.Arduino['math_round'] = Blockly.Arduino['math_single'];
/** Trigonometry functions have a single operand. */
Blockly.Arduino['math_trig'] = Blockly.Arduino['math_single'];
/**
* Generator for the math function to a list.
* Arduino code: ???
* TODO: List have to be implemented first. Removed from toolbox for now.
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_on_list'] = Blockly.Arduino.noGeneratorCodeInline;
/**
* Generator for the math modulo function (calculates remainder of X/Y).
* Arduino code: loop { X % Y }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_modulo'] = function (block) {
var argument0 = Blockly.Arduino.valueToCode(block, 'DIVIDEND',
Blockly.Arduino.ORDER_MULTIPLICATIVE) || '0';
var argument1 = Blockly.Arduino.valueToCode(block, 'DIVISOR',
Blockly.Arduino.ORDER_MULTIPLICATIVE) || '0';
var code = argument0 + ' % ' + argument1;
return [code, Blockly.Arduino.ORDER_MULTIPLICATIVE];
};
/**
* Generator for clipping a number(X) between two limits (Y and Z).
* Arduino code: loop { (X < Y ? Y : ( X > Z ? Z : X)) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_constrain'] = function (block) {
// Constrain a number between two limits.
var argument0 = Blockly.Arduino.valueToCode(block, 'VALUE',
Blockly.Arduino.ORDER_NONE) || '0';
var argument1 = Blockly.Arduino.valueToCode(block, 'LOW',
Blockly.Arduino.ORDER_NONE) || '0';
var argument2 = Blockly.Arduino.valueToCode(block, 'HIGH',
Blockly.Arduino.ORDER_NONE) || '0';
var code = '(' + argument0 + ' < ' + argument1 + ' ? ' + argument1 +
' : ( ' + argument0 + ' > ' + argument2 + ' ? ' + argument2 + ' : ' +
argument0 + '))';
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
};
/**
* Generator for a random integer between two numbers (X and Y).
* Arduino code: loop { math_random_int(X, Y); }
* and an aditional math_random_int function
* @param {!Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino['math_random_int'] = function (block) {
var argument0 = Blockly.Arduino.valueToCode(block, 'FROM',
Blockly.Arduino.ORDER_NONE) || '0';
var argument1 = Blockly.Arduino.valueToCode(block, 'TO',
Blockly.Arduino.ORDER_NONE) || '0';
var functionName = Blockly.Arduino.variableDB_.getDistinctName(
'math_random_int', Blockly.Generator.NAME_TYPE);
Blockly.Arduino.setups_['init_rand'] = 'randomSeed(analogRead(0));';
Blockly.Arduino.math_random_int.random_function = functionName;
var func = [
'int ' + Blockly.Arduino.DEF_FUNC_NAME + '(int min, int max) {',
' if (min > max) {',
' // Swap min and max to ensure min is smaller.',
' int temp = min;',
' min = max;',
' max = temp;',
' }',
' return min + (rand() % (max - min + 1));',
'}'];
var funcName = Blockly.Arduino.addFunction('mathRandomInt', func.join('\n'));
var code = funcName + '(' + argument0 + ', ' + argument1 + ')';
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
};
/**
* Generator for a random float from 0 to 1.
* Arduino code: loop { (rand() / RAND_MAX) }
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['math_random_float'] = function (block) {
return ['(rand() / RAND_MAX)', Blockly.Arduino.ORDER_UNARY_POSTFIX];
};
@@ -0,0 +1,30 @@
import * as Blockly from 'blockly/core';
/**
* Code generator to add code into the setup() and loop() functions.
* Its use is not mandatory, but necessary to add manual code to setup().
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['arduino_functions'] = function (block) {
// Edited version of Blockly.Generator.prototype.statementToCode
function statementToCodeNoTab(block, name) {
var targetBlock = block.getInputTargetBlock(name);
var code = Blockly.Arduino.blockToCode(targetBlock);
if (typeof code != 'string') {
throw new Error('Expecting code from statement block "' + targetBlock.type + '".');
}
return code;
}
var setupBranch = Blockly.Arduino.statementToCode(block, 'SETUP_FUNC');
// //var setupCode = Blockly.Arduino.scrub_(block, setupBranch); No comment block
if (setupBranch) {
Blockly.Arduino.setupCode_['mainsetup'] = setupBranch;
}
var loopBranch = statementToCodeNoTab(block, 'LOOP_FUNC');
//var loopcode = Blockly.Arduino.scrub_(block, loopBranch); No comment block
return loopBranch;
};
@@ -0,0 +1,92 @@
import * as Blockly from 'blockly/core';
/*Display Blocks*/
Blockly.Arduino.sensebox_display_beginDisplay = function () {
Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
Blockly.Arduino.libraries_['library_wire'] = '#include <Wire.h>';
Blockly.Arduino.libraries_['library_AdafruitGFX'] = '#include <Adafruit_GFX.h>';
Blockly.Arduino.libraries_['library_AdafruitSSD1306'] = '#include <Adafruit_SSD1306.h>';
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_display'] = '#define OLED_RESET 4\nAdafruit_SSD1306 display(OLED_RESET);';
Blockly.Arduino.setupCode_['sensebox_display_begin'] = 'senseBoxIO.powerI2C(true);\ndelay(2000);\ndisplay.begin(SSD1306_SWITCHCAPVCC, 0x3D);\ndisplay.display();\ndelay(100);\ndisplay.clearDisplay();';
var code = '';
return code;
};
Blockly.Arduino.sensebox_display_clearDisplay = function () {
var code = 'display.clearDisplay();\n';
return code;
};
Blockly.Arduino.sensebox_display_printDisplay = function () {
var x = Blockly.Arduino.valueToCode(this, 'X', Blockly.Arduino.ORDER_ATOMIC) || '0'
var y = Blockly.Arduino.valueToCode(this, 'Y', Blockly.Arduino.ORDER_ATOMIC) || '0'
var printDisplay = Blockly.Arduino.valueToCode(this, 'printDisplay', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
var size = Blockly.Arduino.valueToCode(this, 'SIZE', Blockly.Arduino.ORDER_ATOMIC) || '1'
var color = this.getFieldValue('COLOR');
var code = 'display.setCursor(' + x + ',' + y + ');\n';
code += 'display.setTextSize(' + size + ');\n';
code += 'display.setTextColor(' + color + ');\n';
code += 'display.println(' + printDisplay + ');\n';
return code;
};
Blockly.Arduino.sensebox_display_show = function (block) {
var show = Blockly.Arduino.statementToCode(block, 'SHOW');
var code = '';
code += show;
code += 'display.display();\n';
return code;
};
Blockly.Arduino.sensebox_display_plotDisplay = function () {
var YLabel = Blockly.Arduino.valueToCode(this, 'YLabel', Blockly.Arduino.ORDER_ATOMIC) || 'Y'
var XLabel = Blockly.Arduino.valueToCode(this, 'XLabel', Blockly.Arduino.ORDER_ATOMIC) || 'X'
var Title = Blockly.Arduino.valueToCode(this, 'Title', Blockly.Arduino.ORDER_ATOMIC) || 'Title'
var XRange1 = Blockly.Arduino.valueToCode(this, 'XRange1', Blockly.Arduino.ORDER_ATOMIC) || '0'
var XRange2 = Blockly.Arduino.valueToCode(this, 'XRange2', Blockly.Arduino.ORDER_ATOMIC) || '0'
var YRange1 = Blockly.Arduino.valueToCode(this, 'YRange1', Blockly.Arduino.ORDER_ATOMIC) || '0'
var YRange2 = Blockly.Arduino.valueToCode(this, 'YRange2', Blockly.Arduino.ORDER_ATOMIC) || '0'
var XTick = Blockly.Arduino.valueToCode(this, 'XTick', Blockly.Arduino.ORDER_ATOMIC) || '0'
var YTick = Blockly.Arduino.valueToCode(this, 'YTick', Blockly.Arduino.ORDER_ATOMIC) || '0'
var TimeFrame = Blockly.Arduino.valueToCode(this, 'TimeFrame', Blockly.Arduino.ORDER_ATOMIC) || '0'
var plotDisplay = Blockly.Arduino.valueToCode(this, 'plotDisplay', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
Blockly.Arduino.libraries_['library_plot'] = '#include <Plot.h>';
Blockly.Arduino.definitions_['define_plot_class'] = 'Plot DataPlot(&display);\n';
Blockly.Arduino.variables_['define_plot_class'] = 'const double TIMEFRAME = ' + TimeFrame + ';\n';
Blockly.Arduino.setupCode_['sensebox_plot_setup'] = 'DataPlot.setTitle(' + Title + ');\nDataPlot.setXLabel(' + XLabel + ');\nDataPlot.setYLabel(' + YLabel + ');\nDataPlot.setXRange(' + XRange1 + ',' + XRange2 + ');\nDataPlot.setYRange(' + YRange1 + ',' + YRange2 + ');\nDataPlot.setXTick(' + XTick + ');\nDataPlot.setYTick(' + YTick + ');\nDataPlot.setXPrecision(0);\nDataPlot.setYPrecision(0);\n';
var code = 'DataPlot.clear();'
code += 'double starttime = millis();\ndouble t = 0;\nwhile (t <= TIMEFRAME) {\nt = (millis() - starttime) / 1000.0;\nfloat value = ' + plotDisplay + ';\n';
code += 'DataPlot.addDataPoint(t,value);\n}\n';
return code;
};
Blockly.Arduino.sensebox_display_fillCircle = function () {
let code = '';
var x = Blockly.Arduino.valueToCode(this, 'X', Blockly.Arduino.ORDER_ATOMIC) || '0'
var y = Blockly.Arduino.valueToCode(this, 'Y', Blockly.Arduino.ORDER_ATOMIC) || '0'
var radius = Blockly.Arduino.valueToCode(this, 'Radius', Blockly.Arduino.ORDER_ATOMIC) || '0'
var fill = this.getFieldValue('FILL');
if (fill === 'TRUE') {
code = 'display.fillCircle(' + x + ',' + y + ',' + radius + ',1);\n';
}
else {
code = 'display.drawCircle(' + x + ',' + y + ',' + radius + ',1);\n';
}
return code;
}
Blockly.Arduino.sensebox_display_drawRectangle = function () {
let code = '';
var x = Blockly.Arduino.valueToCode(this, 'X', Blockly.Arduino.ORDER_ATOMIC) || '0'
var y = Blockly.Arduino.valueToCode(this, 'Y', Blockly.Arduino.ORDER_ATOMIC) || '0'
var width = Blockly.Arduino.valueToCode(this, 'width', Blockly.Arduino.ORDER_ATOMIC) || '0'
var height = Blockly.Arduino.valueToCode(this, 'height', Blockly.Arduino.ORDER_ATOMIC) || '0'
var fill = this.getFieldValue('FILL');
if (fill === 'TRUE') {
code = 'display.fillRect(' + x + ',' + y + ',' + width + ',' + height + ',1);\n';
}
else {
code = 'display.drawRect(' + x + ',' + y + ',' + width + ',' + height + ',1);\n';
}
return code;
}
@@ -0,0 +1,22 @@
import * as Blockly from 'blockly/core';
Blockly.Arduino.sensebox_led = function () {
var dropdown_pin = this.getFieldValue('PIN');
var dropdown_stat = this.getFieldValue('STAT');
Blockly.Arduino.setupCode_['setup_led_' + dropdown_pin] = 'pinMode(' + dropdown_pin + ', OUTPUT);';
var code = 'digitalWrite(' + dropdown_pin + ',' + dropdown_stat + ');\n'
return code;
};
Blockly.Arduino.sensebox_rgb_led = function () {
var dropdown_pin = this.getFieldValue('PIN');
var red = this.getFieldValue('RED') || '0'
var green = this.getFieldValue('GREEN') || '0'
var blue = this.getFieldValue('BLUE') || '0'
Blockly.Arduino.libraries_['define_rgb_led' + dropdown_pin] = '#include <Adafruit_NeoPixel.h>\n Adafruit_NeoPixel rgb_led_' + dropdown_pin + ' = Adafruit_NeoPixel(1,' + dropdown_pin + ',NEO_RGB + NEO_KHZ800);\n';
Blockly.Arduino.setupCode_['setup_rgb_led' + dropdown_pin] = 'rgb_led_' + dropdown_pin + '.begin();';
var code = 'rgb_led_' + dropdown_pin + '.setPixelColor(0,rgb_led_' + dropdown_pin + '.Color(' + red + ',' + green + ',' + blue + '));\n';
code += 'rgb_led_' + dropdown_pin + '.show();';
return code;
};
@@ -0,0 +1,431 @@
import * as Blockly from 'blockly/core';
Blockly.Arduino.sensebox_lora_initialize_otaa = function (block) {
var deivceID = this.getFieldValue('DEVICEID');
var appID = this.getFieldValue('APPID');
var appKey = this.getFieldValue('APPKEY');
var interval = this.getFieldValue('INTERVAL');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
Blockly.Arduino.libraries_['library_lmic'] = '#include <lmic.h>';
Blockly.Arduino.libraries_['library_hal'] = '#include <hal/hal.h>';
Blockly.Arduino.definitions_['define_LoRaVariablesOTAA'] = `
static const u1_t PROGMEM APPEUI[8]= `+ appID + ` ;
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI , 8);}
static const u1_t PROGMEM DEVEUI[8]= `+ deivceID + `;
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI , 8);}
// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = `+ appKey + `;
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY , 16);}
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = ${interval * 60};
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = PIN_XB1_CS,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {PIN_XB1_INT, PIN_XB1_INT, LMIC_UNUSED_PIN},
};`;
Blockly.Arduino.codeFunctions_['functions_initLora'] = `
void initLora() {
delay(2000);
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}`
Blockly.Arduino.codeFunctions_['functions_onEvent'] = `
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
// Disable link check validation (automatically enabled
// during join, but not supported by TTN at this time).
LMIC_setLinkCheckMode(0);
break;
case EV_RFU1:
Serial.println(F("EV_RFU1"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
default:
Serial.println(F("Unknown event"));
break;
}
}`;
Blockly.Arduino.setupCode_['initLora'] = 'initLora();';
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);';
var code = ''
return code;
};
Blockly.Arduino.sensebox_lora_message_send = function (block) {
Blockly.Arduino.libraries_['library_lora_message'] = '#include <LoraMessage.h>';
var lora_sensor_values = Blockly.Arduino.statementToCode(block, 'DO');
Blockly.Arduino.functionNames_['functions_do_send'] = `
void do_send(osjob_t* j){
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
LoraMessage message;
${lora_sensor_values}
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, message.getBytes(), message.getLength(), 0);
Serial.println(F("Packet queued"));
}
// Next TX is scheduled after TX_COMPLETE event.
}`;
Blockly.Arduino.loopCodeOnce_['os_runloop'] = 'os_runloop_once();'
return ''
}
/**
* Block send Data to TTN
*/
Blockly.Arduino.sensebox_send_lora_sensor_value = function (block) {
const reading = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
var messageBytes = this.getFieldValue('MESSAGE_BYTES');
var code = ''
switch (Number(messageBytes)) {
case 1:
code = `message.addUint8(${reading});\n`
break;
case 2:
code = `message.addUint16(${reading});\n`
break;
case 3:
code = `message.addUint8(${reading});
message.addUint16(${reading} >> 8);\n`
break;
default:
code = `message.addUint16(${reading});\n`
}
return code;
};
Blockly.Arduino.sensebox_lora_cayenne_send = function (block) {
Blockly.Arduino.libraries_['library_cayene'] = '#include <CayenneLPP.h>';
Blockly.Arduino.variables_['variable_cayenne'] = 'CayenneLPP lpp(51);'
var lora_sensor_values = Blockly.Arduino.statementToCode(block, 'DO');
Blockly.Arduino.functionNames_['functions_do_send'] = `
void do_send(osjob_t* j){
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
lpp.reset();
${lora_sensor_values}
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0);
Serial.println(F("Packet queued"));
}
// Next TX is scheduled after TX_COMPLETE event.
}`;
Blockly.Arduino.loopCodeOnce_['os_runloop'] = 'os_runloop_once();'
return '';
}
Blockly.Arduino.sensebox_lora_initialize_abp = function (block) {
var nwskey = this.getFieldValue('NWSKEY');
var appskey = this.getFieldValue('APPSKEY');
var devaddr = this.getFieldValue('DEVADDR');
var interval = this.getFieldValue('INTERVAL');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
Blockly.Arduino.libraries_['library_lmic'] = '#include <lmic.h>';
Blockly.Arduino.libraries_['library_hal'] = '#include <hal/hal.h>';
Blockly.Arduino.definitions_['define_LoRaVariablesABP'] = `
// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const PROGMEM u1_t NWKSKEY[16] = ${nwskey};
// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const u1_t PROGMEM APPSKEY[16] = ${appskey};
// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x${devaddr};
// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = ${interval * 60};
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = PIN_XB1_CS,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {PIN_XB1_INT, PIN_XB1_INT, LMIC_UNUSED_PIN},
};`;
Blockly.Arduino.codeFunctions_['functions_initLora'] = `
void initLora() {
delay(2000);
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// Set static session parameters. Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
#ifdef PROGMEM
// On AVR, these values are stored in flash and only copied to RAM
// once. Copy them to a temporary buffer here, LMIC_setSession will
// copy them into a buffer of its own again.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
#else
// If not running an AVR with PROGMEM, just use the arrays directly
LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
#endif
#if defined(CFG_eu868)
// Set up the channels used by the Things Network, which corresponds
// to the defaults of most gateways. Without this, only three base
// channels from the LoRaWAN specification are used, which certainly
// works, so it is good for debugging, but can overload those
// frequencies, so be sure to configure the full frequency range of
// your network here (unless your network autoconfigures them).
// Setting up channels should happen after LMIC_setSession, as that
// configures the minimal channel set.
// NA-US channels 0-71 are configured automatically
LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band
// TTN defines an additional channel at 869.525Mhz using SF9 for class B
// devices' ping slots. LMIC does not have an easy way to define set this
// frequency and support for class B is spotty and untested, so this
// frequency is not configured here.
#elif defined(CFG_us915)
// NA-US channels 0-71 are configured automatically
// but only one group of 8 should (a subband) should be active
// TTN recommends the second sub band, 1 in a zero based count.
// https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
LMIC_selectSubBand(1);
#endif
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF7,14);
// Start job
do_send(&sendjob);
}`
Blockly.Arduino.codeFunctions_['functions_onEvent'] = `
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
break;
case EV_RFU1:
Serial.println(F("EV_RFU1"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
default:
Serial.println(F("Unknown event"));
break;
}
}`;
Blockly.Arduino.setupCode_['initLora'] = 'initLora();';
Blockly.Arduino.setupCode_['serial.begin'] = 'Serial.begin(9600);';
return '';
}
Blockly.Arduino.sensebox_lora_cayenne_temperature = function (block) {
var temperature = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addTemperature(${channel}, ${temperature});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_humidity = function (block) {
var humidity = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addRelativeHumidity(${channel}, ${humidity});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_pressure = function (block) {
var pressure = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addBarometricPressure(${channel}, ${pressure});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_luminosity = function (block) {
var luminosity = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addLuminosity(${channel}, ${luminosity});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_sensor = function (block) {
var sensorValue = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addAnalogInput(${channel}, ${sensorValue});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_accelerometer = function (block) {
var x = Blockly.Arduino.valueToCode(this, 'X', Blockly.Arduino.ORDER_ATOMIC) || 0
var y = Blockly.Arduino.valueToCode(this, 'Y', Blockly.Arduino.ORDER_ATOMIC) || 0
var z = Blockly.Arduino.valueToCode(this, 'Z', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addAccelerometer(${channel}, ${x}, ${y}, ${z});\n`;
return code;
}
Blockly.Arduino.sensebox_lora_cayenne_gps = function (block) {
var lat = Blockly.Arduino.valueToCode(this, 'LAT', Blockly.Arduino.ORDER_ATOMIC) || 0
var lng = Blockly.Arduino.valueToCode(this, 'LNG', Blockly.Arduino.ORDER_ATOMIC) || 0
var alt = Blockly.Arduino.valueToCode(this, 'ALT', Blockly.Arduino.ORDER_ATOMIC) || 0
var channel = this.getFieldValue('CHANNEL');
var code = `lpp.addGPS(${channel}, ${lat}, ${lng}, ${alt});\n`
return code;
}
@@ -0,0 +1,176 @@
import Blockly from 'blockly';
/**
* Block send Data to the openSenseMap
*/
Blockly.Arduino.sensebox_send_to_osem = function (block) {
var code = '';
var sensor_id = this.getFieldValue('SensorID');
var id = sensor_id.slice(-3).toUpperCase();
var sensor_value = Blockly.Arduino.valueToCode(this, 'Value', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
Blockly.Arduino.definitions_['SENSOR_ID' + id + ''] = 'const char SENSOR_ID' + id + '[] PROGMEM = "' + sensor_id + '";';
code += 'addMeasurement(SENSOR_ID' + id + ',' + sensor_value + ');\n';
return code;
};
Blockly.Arduino.sensebox_osem_connection = function (Block) {
var box_id = this.getFieldValue('BoxID');
var host = this.getFieldValue('host');
var branch = Blockly.Arduino.statementToCode(Block, 'DO');
//var blocks = Blockly.Block.getDescendants;
var type = this.getFieldValue('type');
var ssl = this.getFieldValue('SSL');
var port = 0;
var count = 0;
// for (var i = 0; i < blocks.length; i++) {
// if (blocks[i].type === 'sensebox_send_to_osem') {
// count++;
// }
// }
var num_sensors = count;
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['num_sensors'] = 'static const uint8_t NUM_SENSORS = ' + num_sensors + ';'
Blockly.Arduino.definitions_['SenseBoxID'] = 'const char SENSEBOX_ID [] PROGMEM = "' + box_id + '";';
Blockly.Arduino.definitions_['host'] = 'const char server [] PROGMEM =' + host + ';';
if (ssl === 'TRUE') {
Blockly.Arduino.definitions_['WiFiSSLClient'] = 'WiFiSSLClient client;';
port = 443;
} else if (ssl === 'FALSE') {
Blockly.Arduino.definitions_['WiFiClient'] = 'WiFiClient client;';
port = 80;
}
Blockly.Arduino.definitions_['measurement'] = `typedef struct measurement {
const char *sensorId;
float value;
} measurement;`;
Blockly.Arduino.definitions_['buffer'] = 'char buffer[750];';
Blockly.Arduino.definitions_['num_measurement'] = `measurement measurements[NUM_SENSORS];
uint8_t num_measurements = 0;`;
Blockly.Arduino.definitions_['lengthMultiplikator'] = 'const int lengthMultiplikator = 35;';
Blockly.Arduino.functionNames_['addMeasurement'] = `
void addMeasurement(const char *sensorId, float value) {
measurements[num_measurements].sensorId = sensorId;
measurements[num_measurements].value = value;
num_measurements++;
}`;
if (type === 'Stationary') {
Blockly.Arduino.functionNames_['writeMeasurementsToClient'] = `
void writeMeasurementsToClient() {
// iterate throug the measurements array
for (uint8_t i = 0; i < num_measurements; i++) {
sprintf_P(buffer, PSTR("%s,%9.2f\\n"), measurements[i].sensorId,
measurements[i].value);
// transmit buffer to client
client.print(buffer);
}
// reset num_measurements
num_measurements = 0;
}`;
Blockly.Arduino.functionNames_['submitValues'] = `
void submitValues() {
if (client.connected()) {
client.stop();
delay(10);
}
bool connected = false;
char _server[strlen_P(server)];
strcpy_P(_server, server);
for (uint8_t timeout = 2; timeout != 0; timeout--) {
Serial.println(F("connecting..."));
connected = client.connect(_server, `+ port + `);
if (connected == true) {
// construct the HTTP POST request:
sprintf_P(buffer,
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
// send the HTTP POST request:
client.print(buffer);
// send measurements
writeMeasurementsToClient();
// send empty line to end the request
client.println();
uint16_t timeout = 0;
// allow the response to be computed
while (timeout <= 5000) {
delay(10);
timeout = timeout + 10;
if (client.available()) {
break;
}
}
num_measurements = 0;
break;
}
}
}`;
var code = '';
code += branch;
code += "submitValues();\n";
}
else if (type === 'Mobile') {
var lat = Blockly.Arduino.valueToCode(Block, 'lat', Blockly.Arduino.ORDER_ATOMIC);
var lng = Blockly.Arduino.valueToCode(Block, 'lng', Blockly.Arduino.ORDER_ATOMIC);
var timestamp = Blockly.Arduino.valueToCode(Block, 'timeStamp', Blockly.Arduino.ORDER_ATOMIC);
var altitude = Blockly.Arduino.valueToCode(Block, 'altitude', Blockly.Arduino.ORDER_ATOMIC);
Blockly.Arduino.definitions_['lengthMultiplikator'] = 'const int lengthMultiplikator = 77;';
Blockly.Arduino.functionNames_['writeMeasurementsToClient'] = `
void writeMeasurementsToClient(float lat, float lng, float altitude, char* timeStamp) {
// iterate throug the measurements array
for (uint8_t i = 0; i < num_measurements; i++) {
sprintf_P(buffer, PSTR("%s,%9.2f,%s,%3.6f,%3.6f,%5.2f\\n"), measurements[i].sensorId,
measurements[i].value, timeStamp, lng, lat, altitude);
// transmit buffer to client
client.print(buffer);
}
// reset num_measurements
num_measurements = 0;
}`;
Blockly.Arduino.functionNames_['submitValues'] = `
void submitValues(float lat, float lng, float altitude, char* timeStamp) {
if (client.connected()) {
client.stop();
delay(10);
}
bool connected = false;
char _server[strlen_P(server)];
strcpy_P(_server, server);
for (uint8_t timeout = 2; timeout != 0; timeout--) {
Serial.println(F("connecting..."));
connected = client.connect(_server, `+ port + `);
if (connected == true) {
// construct the HTTP POST request:
sprintf_P(buffer,
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
// send the HTTP POST request:
client.print(buffer);
// send measurements
writeMeasurementsToClient(lat, lng, altitude, timeStamp);
// send empty line to end the request
client.println();
uint16_t timeout = 0;
// allow the response to be computed
while (timeout <= 5000) {
delay(10);
timeout = timeout + 10;
if (client.available()) {
break;
}
}
num_measurements = 0;
break;
}
}
}`
code = '';
code += branch;
code += 'submitValues(' + lat + ',' + lng + ',' + altitude + ',' + timestamp + ');\n';
}
return code;
};
@@ -0,0 +1,54 @@
import Blockly from 'blockly';
/* SD-Card Blocks using the Standard SD Library*/
/**
* Code generator for variable (X) getter.
* Arduino code: loop { X }
* @param {Blockly.Block} block Block to generate the code from.
* @return {array} Completed code with order of operation.
*/
Blockly.Arduino.sensebox_sd_create_file = function (block) {
var filename = this.getFieldValue('Filename');
var res = filename.slice(0, 4);
Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
Blockly.Arduino.libraries_['library_sd'] = '#include <SD.h>';
Blockly.Arduino.definitions_['define_' + res] = 'File dataFile' + res + ';';
Blockly.Arduino.setupCode_['sensebox_sd'] = 'SD.begin(28);';
Blockly.Arduino.setupCode_['sensebox_sd' + filename] = 'dataFile' + res + ' = SD.open("' + filename + '", FILE_WRITE);\ndataFile' + res + '.close();\n';
var code = '';
return code;
};
Blockly.Arduino.sensebox_sd_open_file = function (block) {
var filename = this.getFieldValue('Filename');
var res = filename.slice(0, 4);
var branch = Blockly.Arduino.statementToCode(block, 'SD');
var code = 'dataFile' + res + ' = SD.open("' + filename + '", FILE_WRITE);\n'
code += branch;
code += 'dataFile' + res + '.close();\n'
return code;
};
Blockly.Arduino.sensebox_sd_write_file = function (block) {
if (this.parentBlock_ != null) {
var filename = this.getSurroundParent().getFieldValue('Filename');
}
var res = filename.slice(0, 4);
var text = Blockly.Arduino.valueToCode(this, 'DATA', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
var linebreak = this.getFieldValue('linebreak');
if (linebreak === "TRUE") {
linebreak = "ln";
} else {
linebreak = "";
}
var code = '';
if (text === "gps.getLongitude()" || text === "gps.getLatitude()") {
code = 'dataFile' + res + '.print' + linebreak + '(' + text + ',5);\n'
}
else {
code = 'dataFile' + res + '.print' + linebreak + '(' + text + ');\n'
}
return code;
};
@@ -1,6 +1,298 @@
import * as Blockly from 'blockly/core';
import { Block } from 'blockly';
import Blockly from 'blockly';
Blockly.Arduino['sensebox_telegram'] = function (Block) {
/**
* HDC1080 Temperature and Humidity Sensor
*
*/
Blockly.Arduino.sensebox_sensor_temp_hum = function () {
var dropdown_name = this.getFieldValue('NAME');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_hdc'] = 'HDC1080 hdc;';
Blockly.Arduino.setupCode_['sensebox_sensor_temp_hum'] = 'hdc.begin();';
var code = 'hdc.get' + dropdown_name + '()';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* VEML 6070 and TSL4513 UV-Light/Illuminance Sensor
*
*/
Blockly.Arduino.sensebox_sensor_uv_light = function () {
var dropdown_name = this.getFieldValue('NAME');
let code = '';
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
if (dropdown_name === 'UvIntensity') {
Blockly.Arduino.definitions_['define_veml'] = 'VEML6070 veml;'
Blockly.Arduino.setupCode_['sensebox_sensor_uv_light'] = 'veml.begin();'
code = 'veml.get' + dropdown_name + '()';
}
if (dropdown_name === 'Illuminance') {
Blockly.Arduino.definitions_['define_tsl'] = 'TSL45315 tsl;'
Blockly.Arduino.setupCode_['sensebox_sensor_illuminance'] = 'tsl.begin();'
code = 'tsl.get' + dropdown_name + '()';
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* BMX055 Accelerometer
*
*/
Blockly.Arduino.sensebox_sensor_bmx055_accelerometer = function () {
var dropdown_value = this.getFieldValue('VALUE');
var range = this.getFieldValue('RANGE');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_bmx'] = 'BMX055 bmx;';
Blockly.Arduino.setupCode_['sensebox_sensor_bmx055'] = 'bmx.beginAcc(' + range + ');';
var code = 'bmx.getAcceleration' + dropdown_value + '()';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* SDS011 Fine Particlar Matter
*
*/
Blockly.Arduino.sensebox_sensor_sds011 = function () {
var dropdown_name = this.getFieldValue('NAME');
var serial_name = this.getFieldValue('SERIAL');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.codeFunctions_['define_sds011'] = 'SDS011 my_sds(' + serial_name + ');';
Blockly.Arduino.variables_['variables_sds011'] = 'float p10,p25;\n';
Blockly.Arduino.setupCode_['sensebox_sensor_sds011'] = serial_name + '.begin(9600);';
var code = 'my_sds.get' + dropdown_name + '()';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* BMP280 Pressure Sensor
*
*/
Blockly.Arduino.sensebox_sensor_pressure = function () {
var dropdown_name = this.getFieldValue('NAME');
var code = '';
var referencePressure = this.getFieldValue('referencePressure');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_pressure'] = 'BMP280 bmp_sensor;';
Blockly.Arduino.setupCode_['sensebox_bmp_sensor'] = 'bmp_sensor.begin();';
if (dropdown_name === 'Pressure' || dropdown_name === 'Temperature') {
code = 'bmp_sensor.get' + dropdown_name + '()';
}
else if (dropdown_name === 'Altitude') {
code = 'bmp_sensor.getAltitude(' + referencePressure + ')';
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* BME680 Environmental Sensor
*
*/
Blockly.Arduino.sensebox_sensor_bme680_bsec = function () {
var dropdown_name = this.getFieldValue('dropdown');
let code = '';
Blockly.Arduino.libraries_['library_bsec'] = '#include "bsec.h"';
Blockly.Arduino.definitions_['bsec_iaqSensor'] = 'Bsec iaqSensor;'
Blockly.Arduino.variables_['bmeTemperatur'] = 'float bmeTemperatur;';
Blockly.Arduino.variables_['bmeHumidity'] = 'float bmeHumidity;';
Blockly.Arduino.variables_['bmePressure'] = 'double bmePressure;';
Blockly.Arduino.variables_['bmeIAQ'] = 'float bmeIAQ;';
Blockly.Arduino.variables_['bmeIAQAccuracy'] = 'float bmeIAQAccuracy;';
Blockly.Arduino.variables_['bmeCO2'] = 'int bmeCO2;';
Blockly.Arduino.variables_['bmeBreathVocEquivalent'] = 'float bmeBreathVocEquivalent;'
Blockly.Arduino.functionNames_['checkIaqSensorStatus'] = `
void checkIaqSensorStatus(void)
{
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
for (;;)
errLeds(); /* Halt in case of failure */
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
for (;;)
errLeds(); /* Halt in case of failure */
}
}
}
`;
Blockly.Arduino.functionNames_['errLeds'] = `
void errLeds(void)
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}`;
//Setup Code
Blockly.Arduino.setupCode_['Wire.begin'] = 'Wire.begin();';
Blockly.Arduino.setupCode_['iaqSensor.begin'] = 'iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire);';
Blockly.Arduino.setupCode_['checkIaqSensorStatus'] = 'checkIaqSensorStatus();';
Blockly.Arduino.setupCode_['bsec_sensorlist'] = `
bsec_virtual_sensor_t sensorList[10] = {
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
};
`;
Blockly.Arduino.setupCode_['iaqSensorUpdateSubscription'] = 'iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);\ncheckIaqSensorStatus();';
//Loop Code
Blockly.Arduino.loopCodeOnce_['iaqloop'] = `
if (iaqSensor.run()) {
bmeTemperatur = iaqSensor.temperature;
bmeHumidity = iaqSensor.humidity;
bmePressure = iaqSensor.pressure;
bmeIAQ = iaqSensor.iaq;
bmeIAQAccuracy = iaqSensor.iaqAccuracy;
bmeCO2 = iaqSensor.co2Equivalent;
bmeBreathVocEquivalent = iaqSensor.breathVocEquivalent;
} else {
checkIaqSensorStatus();
}
`;
switch (dropdown_name) {
case 'temperature':
code = 'bmeTemperatur';
break;
case 'humidity':
code = 'bmeHumidity';
break;
case 'pressure':
code = 'bmePressure'
break;
case 'IAQ':
code = 'bmeIAQ';
break;
case 'IAQAccuracy':
code = 'bmeIAQAccuracy';
break;
case 'CO2':
code = 'bmeCO2';
break;
case 'breathVocEquivalent':
code = 'bmeBreathVocEquivalent';
break;
default:
break;
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Ultrasonic Distance Sensor
*
*/
Blockly.Arduino.sensebox_sensor_ultrasonic_ranger = function () {
var dropdown_pin_RX = this.getFieldValue('ultrasonic_trigger');
var dropdown_pin_TX = this.getFieldValue('ultrasonic_echo');
var port = this.getFieldValue('port');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['var_ultrasonic' + port] = 'Ultrasonic Ultrasonic' + port + '(' + dropdown_pin_RX + ',' + dropdown_pin_TX + ');';
var code;
code = 'Ultrasonic' + port + '.getDistance()';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Microphone
*
*/
Blockly.Arduino.sensebox_sensor_sound = function () {
var dropdown_pin = this.getFieldValue('PIN');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_microphone'] = 'Microphone microphone(' + dropdown_pin + ');'
var code = 'microphone.getValue()';
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* Button
*
*/
Blockly.Arduino.sensebox_button = function () {
var dropdown_pin = this.getFieldValue('PIN');
var dropown_function = this.getFieldValue('FUNCTION');
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['define_button' + dropdown_pin + ''] = 'Button button_' + dropdown_pin + '(' + dropdown_pin + ');';
Blockly.Arduino.setupCode_['setup_button' + dropdown_pin + ''] = 'button_' + dropdown_pin + '.begin();';
var code = '';
if (dropown_function === 'isPressed') {
code = 'button_' + dropdown_pin + '.isPressed()';
}
else if (dropown_function === 'Switch') {
code = 'button_' + dropdown_pin + '.getSwitch()';
}
else if (dropown_function === 'wasPressed') {
code = 'button_' + dropdown_pin + '.wasPressed()';
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
/**
* SCD30 CO2 Sensor
*
*/
Blockly.Arduino.sensebox_scd30 = function () {
var dropdown = this.getFieldValue('dropdown');
Blockly.Arduino.libraries_['scd30_library'] = '#include "SparkFun_SCD30_Arduino_Library.h"'
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['SCD30'] = 'SCD30 airSensor;';
Blockly.Arduino.variables_['scd30_temp'] = 'float scd30_temp;';
Blockly.Arduino.variables_['scd30_humi'] = 'float scd30_humi;';
Blockly.Arduino.variables_['scd30_co2'] = 'float scd30_co2;';
Blockly.Arduino.setupCode_['init_scd30'] = ` Wire.begin();
if (airSensor.begin() == false)
{
Serial.println("Air sensor not detected. Please check wiring. Freezing...");
while (1)
;
}`;
Blockly.Arduino.loopCodeOnce_['scd30_getData'] = `if (airSensor.dataAvailable())
{
scd30_co2 = airSensor.getCO2();
scd30_temp = airSensor.getTemperature();
scd30_humi = airSensor.getHumidity();
}`
var code = '';
switch (dropdown) {
case 'temperature':
code = 'scd30_temp';
break;
case 'humidity':
code = 'scd30_humi';
break;
case 'CO2':
code = 'scd30_co2';
break;
default:
code = ''
}
return [code, Blockly.Arduino.ORDER_ATOMIC];
}
@@ -0,0 +1,57 @@
import * as Blockly from 'blockly/core';
/**
* Telegram Bot by re:edu
*/
Blockly.Arduino.sensebox_telegram = function (Block) {
let token = Block.getFieldValue('telegram_token');
Blockly['Arduino'].libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly['Arduino'].libraries_['library_telegram'] = `#include <UniversalTelegramBot.h>`
Blockly['Arduino'].functionNames_['WiFiSSLClient'] = 'WiFiSSLClient client;';
Blockly['Arduino'].functionNames_['telegram_objects'] = `#define BOTtoken "${token}" // your Bot Token (Get from Botfather)
UniversalTelegramBot bot(BOTtoken, client);`
let code = '';
return code;
};
Blockly.Arduino.sensebox_telegram_do = function (block) {
var messageProcessing = Blockly.Arduino.statementToCode(block, 'telegram_do', Blockly.Arduino.ORDER_ATOMIC);
Blockly.Arduino.definitions_['telegram_variables'] = `int Bot_mtbs = 1000; //mean time between scan messages
long Bot_lasttime; //last time messages' scan has been done`
Blockly.Arduino.loopCodeOnce_['sensebox_telegram_loop'] = `if (millis() > Bot_lasttime + Bot_mtbs) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while(numNewMessages) {
for(int i=0; i<numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
${messageProcessing}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
Bot_lasttime = millis();
}`;
var code = '';
return code;
};
Blockly.Arduino.sensebox_telegram_do_on_message = function (block) {
var message = this.getFieldValue('telegram_message');
var stuffToDo = Blockly.Arduino.statementToCode(block, 'telegram_do_on_message', Blockly.Arduino.ORDER_ATOMIC);
var code = `
if (text == "${message}") {
${stuffToDo}
}`;
return code;
};
Blockly.Arduino.sensebox_telegram_send = function (block) {
var textToSend = Blockly.Arduino.valueToCode(this, 'telegram_text_to_send', Blockly.Arduino.ORDER_ATOMIC) || '"Keine Eingabe"';
var code = `bot.sendMessage(chat_id, String(${textToSend}), "");\n`;
return code;
};

Some files were not shown because too many files have changed in this diff Show More