From 0183679041b2454d107f284f30b25c5915fa7341 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 11 Nov 2020 15:24:33 +0100 Subject: [PATCH 1/3] add webserver blocks --- src/components/Blockly/blocks/index.js | 1 + src/components/Blockly/blocks/webserver.js | 338 ++++++++++++++++++ src/components/Blockly/generator/index.js | 1 + src/components/Blockly/generator/webserver.js | 114 ++++++ src/components/Blockly/helpers/colour.js | 3 +- src/components/Blockly/toolbox/Toolbox.js | 14 + 6 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 src/components/Blockly/blocks/webserver.js create mode 100644 src/components/Blockly/generator/webserver.js diff --git a/src/components/Blockly/blocks/index.js b/src/components/Blockly/blocks/index.js index ae24de3..964c2dc 100644 --- a/src/components/Blockly/blocks/index.js +++ b/src/components/Blockly/blocks/index.js @@ -19,5 +19,6 @@ import './procedures'; import './time'; import './variables'; import './lists'; +import './webserver'; import '../helpers/types' \ No newline at end of file diff --git a/src/components/Blockly/blocks/webserver.js b/src/components/Blockly/blocks/webserver.js new file mode 100644 index 0000000..df34788 --- /dev/null +++ b/src/components/Blockly/blocks/webserver.js @@ -0,0 +1,338 @@ +import Blockly from 'blockly/core'; +import { getColour } from '../helpers/colour'; +import { getCompatibleTypes } from '../helpers/types' +import * as Types from '../helpers/types'; + +/** + * Webserver Blocks By Lucas Steinmann + * */ + +Blockly.Blocks['sensebox_initialize_http_server'] = { + init: function () { + this.setTooltip(Blockly.Msg.senseBox_init_http_server_tip); + this.setHelpUrl('https://sensebox.de/books'); + this.setColour(getColour().webserver); + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_init_http_server); + this.appendDummyInput() + .setAlign(Blockly.ALIGN_LEFT) + .appendField("Port") + .appendField(new Blockly.FieldNumber(80), "Port"); + 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); + }, + LOOP_TYPES: ['arduino_functions'], +}; + + +Blockly.Blocks['sensebox_http_on_client_connect'] = { + init: function () { + this.setTooltip(Blockly.Msg.senseBox_http_on_client_connect_tip); + this.setColour(getColour().webserver); + this.appendDummyInput().appendField(Blockly.Msg.senseBox_http_on_client_connect); + this.appendStatementInput('ON_CONNECT'); + this.setHelpUrl('https://sensebox.de/books'); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + } +}; + + +Blockly.Blocks['sensebox_http_method'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_method) + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_http_method_tip); + this.setHelpUrl('https://sensebox.de/books'); + }, + getBlockType: function () { + return Blockly.Types.TEXT; + }, +}; + + +Blockly.Blocks['sensebox_http_uri'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_uri) + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_http_uri_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; + + +Blockly.Blocks['sensebox_http_protocol_version'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_protocol_version) + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_http_protocol_version_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; + +Blockly.Blocks['sensebox_ip_address'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_ip_address); + this.setTooltip(Blockly.Msg.senseBox_ip_address_tip); + this.setHelpUrl(''); + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + } +}; + +Blockly.Blocks['sensebox_http_user_agent'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_user_agent) + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_http_user_agent_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; + +Blockly.Blocks['sensebox_generate_html_doc'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_html_document); + this.appendValueInput('HEADER') + .setAlign(Blockly.ALIGN_LEFT) + .setCheck(getCompatibleTypes('String')) + .appendField(Blockly.Msg.senseBox_html_header); + this.appendValueInput('BODY') + .setAlign(Blockly.ALIGN_LEFT) + .setCheck(getCompatibleTypes('String')) + .appendField(Blockly.Msg.senseBox_html_body); + this.setInputsInline(false); + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_html_document_tip); + this.setHelpUrl('https://sensebox.de/books'); + }, +}; + +Blockly.Blocks['sensebox_generate_http_succesful_response'] = { + init: function () { + this.setColour(getColour().webserver); + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_success); + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_http_success_l2); + this.appendValueInput('CONTENT') + .appendField(Blockly.Msg.senseBox_http_success_buildhtml) + .setCheck(getCompatibleTypes('String')); + this.setTooltip(Blockly.Msg.senseBox_http_success_tip); + this.setInputsInline(false); + this.setHelpUrl('https://sensebox.de/books'); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + } +}; + +Blockly.Blocks['sensebox_generate_http_not_found_response'] = { + init: function () { + this.setTooltip(Blockly.Msg.senseBox); + this.setColour(getColour().webserver); + this.appendDummyInput().appendField(Blockly.Msg.senseBox_http_not_found); + this.setTooltip(Blockly.Msg.senseBox_http_not_found_tip); + this.setHelpUrl('https://sensebox.de/books'); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + } +}; + + +Blockly.Blocks['sensebox_general_html_tag'] = { + init: function () { + this.setTooltip(Blockly.Msg.senseBox_html_general_tag_tip); + this.setColour(getColour().webserver); + this.appendDummyInput() + .appendField("<") + .appendField(new Blockly.FieldTextInput("Tag"), "TAG") + .appendField(">"); + this.appendValueInput('DO0') + .setCheck(getCompatibleTypes('String')); + this.setInputsInline(false); + this.setOutput(true, Types.TEXT.typeName); + this.setHelpUrl('https://sensebox.de/books'); + this.setPreviousStatement(false); + this.setNextStatement(false); + this.setMutator(new Blockly.Mutator(['additional_child'])); + var thisBlock = this; + this.additionalChildCount_ = 0; + }, + /** + * Create XML to represent the number of else-if and else inputs. + * @return {Element} XML storage element. + * @this Blockly.Block + */ + mutationToDom: function () { + if (!this.additionalChildCount_) { + return null; + } + var container = document.createElement('mutation'); + if (this.additionalChildCount_) { + container.setAttribute('add_child', this.additionalChildCount_); + } + return container; + }, + /** + * Parse XML to restore the else-if and else inputs. + * @param {!Element} xmlElement XML storage element. + * @this Blockly.Block + */ + domToMutation: function (xmlElement) { + this.additionalChildCount_ = parseInt(xmlElement.getAttribute('add_child'), 10) || 0; + this.updateShape_(); + }, + /** + * Populate the mutator's dialog with this block's components. + * @param {!Blockly.Workspace} workspace Mutator's workspace. + * @return {!Blockly.Block} Root block in mutator. + * @this Blockly.Block + */ + decompose: function (workspace) { + var containerBlock = workspace.newBlock('first_child'); + containerBlock.initSvg(); + var connection = containerBlock.nextConnection; + for (var i = 1; i <= this.additionalChildCount_; i++) { + var elseifBlock = workspace.newBlock('additional_child'); + elseifBlock.initSvg(); + connection.connect(elseifBlock.previousConnection); + connection = elseifBlock.nextConnection; + } + return containerBlock; + }, + /** + * Reconfigure this block based on the mutator dialog's components. + * @param {!Blockly.Block} containerBlock Root block in mutator. + * @this Blockly.Block + */ + compose: function (containerBlock) { + var clauseBlock = containerBlock.nextConnection.targetBlock(); + // Count number of inputs. + this.additionalChildCount_ = 0; + var statementConnections = [null]; + var elseStatementConnection = null; + while (clauseBlock) { + switch (clauseBlock.type) { + case 'additional_child': + this.additionalChildCount_++; + statementConnections.push(clauseBlock.statementConnection_); + break; + default: + throw 'Unknown block type.'; + } + clauseBlock = clauseBlock.nextConnection && + clauseBlock.nextConnection.targetBlock(); + } + this.updateShape_(); + // Reconnect any child blocks. + for (var i = 1; i <= this.additionalChildCount_; i++) { + Blockly.Mutator.reconnect(statementConnections[i], this, 'DO' + i); + } + }, + /** + * Store pointers to any connected child blocks. + * @param {!Blockly.Block} containerBlock Root block in mutator. + * @this Blockly.Block + */ + saveConnections: function (containerBlock) { + var clauseBlock = containerBlock.nextConnection.targetBlock(); + var i = 1; + while (clauseBlock) { + switch (clauseBlock.type) { + case 'additional_child': + var inputDo = this.getInput('DO' + i); + clauseBlock.statementConnection_ = + inputDo && inputDo.connection.targetConnection; + i++; + break; + default: + throw 'Unknown block type.'; + } + clauseBlock = clauseBlock.nextConnection && + clauseBlock.nextConnection.targetBlock(); + } + }, + /** + * Modify this block to have the correct number of inputs. + * @private + * @this Blockly.Block + */ + updateShape_: function () { + // Delete everything. + var i = 1; + while (this.getInput('DO' + i)) { + this.removeInput('DO' + i); + i++; + } + // Rebuild block. + for (var i = 1; i <= this.additionalChildCount_; i++) { + this.appendValueInput('DO' + i, Blockly.Arduino.ORDER_NONE); + } + } +}; + +Blockly.Blocks['first_child'] = { + init: function () { + this.setColour(Blockly.Blocks.logic.HUE); + this.appendDummyInput() + .appendField(""); + this.setNextStatement(true); + this.setInputsInline(true); + this.setTooltip(Blockly.Msg.senseBox_tag_first_mutator_tip); + this.contextMenu = false; + } +}; + + +Blockly.Blocks['additional_child'] = { + init: function () { + this.setColour(Blockly.Blocks.logic.HUE); + this.appendDummyInput() + .appendField(""); + this.setPreviousStatement(true); + this.setInputsInline(true); + this.setNextStatement(true); + this.setTooltip(Blockly.Msg.senseBox_tag_optional_mutator_tip); + this.contextMenu = false; + } +}; + +// Additional Webserver Blocks + +Blockly.Blocks['sensebox_web_readHTML'] = { + init: function () { + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_sd_web_readHTML) + .setAlign(Blockly.ALIGN_LEFT); + this.appendDummyInput() + .setAlign(Blockly.ALIGN_LEFT) + .appendField(Blockly.Msg.sensebox_web_readHTML_filename) + .appendField(new Blockly.FieldTextInput("index.txt"), "FILENAME"); + this.setOutput(true, Types.TEXT.typeName); + this.setColour(getColour().webserver); + this.setTooltip(Blockly.Msg.senseBox_output_safetosd_tip); + this.setHelpUrl('https://sensebox.de/books'); + } +}; \ No newline at end of file diff --git a/src/components/Blockly/generator/index.js b/src/components/Blockly/generator/index.js index 8f6859c..04f337f 100644 --- a/src/components/Blockly/generator/index.js +++ b/src/components/Blockly/generator/index.js @@ -19,5 +19,6 @@ import './procedures'; import './time'; import './variables'; import './lists'; +import './webserver'; diff --git a/src/components/Blockly/generator/webserver.js b/src/components/Blockly/generator/webserver.js new file mode 100644 index 0000000..0cbee13 --- /dev/null +++ b/src/components/Blockly/generator/webserver.js @@ -0,0 +1,114 @@ +import Blockly from 'blockly'; +/** + * Webserver Blocks by Lucas Steinmann + * + */ + +Blockly.Arduino.sensebox_initialize_http_server = function (block) { + var box_id = this.getFieldValue('Port'); + Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"'; + Blockly.Arduino.codeFunctions_['define_wifi_server'] = 'WiFiServer server(' + box_id + ');'; + Blockly.Arduino.setupCode_['sensebox_wifi_server_beging'] = 'server.begin();'; + return ''; +}; + +Blockly.Arduino.sensebox_http_on_client_connect = function (block) { + var onConnect = Blockly.Arduino.statementToCode(block, 'ON_CONNECT'); + var code = ''; + code += 'WiFiClient client = server.available();\n'; + code += 'if (client && client.available()) {\n'; + code += ' String request_string = listenClient(client);\n'; + code += ' Request request;\n'; + code += ' if (parseRequestSafe(request_string, request)) {\n'; + code += onConnect; + code += ' }\n'; + code += ' delay(1);\n'; + code += ' client.stop();\n'; + code += ' delay(1);\n'; + code += '}\n'; + return code; +}; + +Blockly.Arduino.sensebox_http_method = function (block) { + var code = "request.method"; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + + +Blockly.Arduino.sensebox_http_uri = function (block) { + var code = "request.uri"; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_http_protocol_version = function (block) { + var code = "request.protocol_version"; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_http_user_agent = function (block) { + var code = "request.user_agent"; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_generate_html_doc = function (block) { + var header = Blockly.Arduino.valueToCode(block, 'HEADER', Blockly.Arduino.ORDER_NONE) || '""'; + var body = Blockly.Arduino.valueToCode(block, 'BODY', Blockly.Arduino.ORDER_NONE) || '""'; + var code = 'buildHTML(' + header + ', ' + body + ')'; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_generate_http_succesful_response = function (block) { + var content = Blockly.Arduino.valueToCode(block, 'CONTENT', Blockly.Arduino.ORDER_NONE) || '""'; + var code = 'client.println(buildSuccessfulResponse(request, ' + content + '));\n'; + return code; +}; + +Blockly.Arduino.sensebox_generate_http_not_found_response = function (block) { + var code = 'client.println(buildNotFoundResponse(request));\n'; + return code; +}; + + +Blockly.Arduino.sensebox_ip_address = function (block) { + var code = "b->getIpAddress()"; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_general_html_tag = function (block) { + var tag = this.getFieldValue('TAG'); + var code = 'buildTag("' + tag + '",'; + var n = 0; + var branch = Blockly.Arduino.valueToCode(block, 'DO' + n, Blockly.Arduino.ORDER_NONE); + if (branch.length > 0) { + code += '\n ' + branch; + } else { + code += '""'; + } + for (n = 1; n <= block.additionalChildCount_; n++) { + branch = Blockly.Arduino.valueToCode(block, 'DO' + n, Blockly.Arduino.ORDER_NONE); + code += ' +' + branch; + } + return [code + ')', Blockly.Arduino.ORDER_ATOMIC]; +}; + +Blockly.Arduino.sensebox_web_readHTML = function (block) { + var filename = this.getFieldValue('FILENAME'); + Blockly.Arduino.libraries_['library_spi'] = '#include '; + Blockly.Arduino.libraries_['library_sd'] = '#include '; + Blockly.Arduino.codeFunctions_['define_sd' + filename] = 'File webFile;'; + Blockly.Arduino.setupCode_['sensebox_sd'] = 'SD.begin(28);'; + var func = [ + 'String generateHTML(){', + ' webFile = SD.open("' + filename + '", FILE_READ);', + ' String finalString ="";', + ' while (webFile.available())', + ' {', + ' finalString+=(char)webFile.read();', + ' }', + ' return finalString;', + '}']; + var functionName = Blockly.Arduino.addFunction( + 'generateHTML', func.join('\n')); + var code = functionName + '()'; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +}; \ No newline at end of file diff --git a/src/components/Blockly/helpers/colour.js b/src/components/Blockly/helpers/colour.js index 8813d0e..0b3c1fb 100644 --- a/src/components/Blockly/helpers/colour.js +++ b/src/components/Blockly/helpers/colour.js @@ -11,7 +11,8 @@ const colours = { variables: 330, audio: 250, arrays: 33, - mqtt: 90 + mqtt: 90, + webserver: 40 } diff --git a/src/components/Blockly/toolbox/Toolbox.js b/src/components/Blockly/toolbox/Toolbox.js index 23b7fcc..96d8db2 100644 --- a/src/components/Blockly/toolbox/Toolbox.js +++ b/src/components/Blockly/toolbox/Toolbox.js @@ -282,6 +282,20 @@ class Toolbox extends React.Component { + + + + + + + + + + + + + + From dad91d0a93238824572c4654e9637f83380e76c6 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 11 Nov 2020 15:29:56 +0100 Subject: [PATCH 2/3] resolve warnings --- src/components/Blockly/blocks/mqtt.js | 3 +-- src/components/Blockly/blocks/webserver.js | 12 ++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/components/Blockly/blocks/mqtt.js b/src/components/Blockly/blocks/mqtt.js index f024e8f..00bc502 100644 --- a/src/components/Blockly/blocks/mqtt.js +++ b/src/components/Blockly/blocks/mqtt.js @@ -1,6 +1,5 @@ import * as Blockly from 'blockly/core'; import { getColour } from '../helpers/colour'; -import * as Types from '../helpers/types' /** * MQTT Blocks @@ -36,7 +35,7 @@ Blockly.Blocks["sensebox_mqtt_setup"] = { }, onchange: function (e) { let service = this.getFieldValue('service'); - switch (this.getFieldValue('service')) { + switch (service) { case 'adafruitio': this.getField('server').setValue("io.adafruit.com"); this.getField('port').setValue("1883"); diff --git a/src/components/Blockly/blocks/webserver.js b/src/components/Blockly/blocks/webserver.js index df34788..049bfd9 100644 --- a/src/components/Blockly/blocks/webserver.js +++ b/src/components/Blockly/blocks/webserver.js @@ -22,12 +22,10 @@ Blockly.Blocks['sensebox_initialize_http_server'] = { 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; + if (this.LOOP_TYPES.indexOf(block.type) !== -1) { break; } block = block.getSurroundParent(); @@ -177,7 +175,6 @@ Blockly.Blocks['sensebox_general_html_tag'] = { this.setPreviousStatement(false); this.setNextStatement(false); this.setMutator(new Blockly.Mutator(['additional_child'])); - var thisBlock = this; this.additionalChildCount_ = 0; }, /** @@ -232,7 +229,6 @@ Blockly.Blocks['sensebox_general_html_tag'] = { // Count number of inputs. this.additionalChildCount_ = 0; var statementConnections = [null]; - var elseStatementConnection = null; while (clauseBlock) { switch (clauseBlock.type) { case 'additional_child': @@ -240,7 +236,7 @@ Blockly.Blocks['sensebox_general_html_tag'] = { statementConnections.push(clauseBlock.statementConnection_); break; default: - throw 'Unknown block type.'; + throw new Error("Unknown block type."); } clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock(); @@ -268,7 +264,7 @@ Blockly.Blocks['sensebox_general_html_tag'] = { i++; break; default: - throw 'Unknown block type.'; + throw new Error('Unknown block type.'); } clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock(); @@ -287,7 +283,7 @@ Blockly.Blocks['sensebox_general_html_tag'] = { i++; } // Rebuild block. - for (var i = 1; i <= this.additionalChildCount_; i++) { + for (i = 1; i <= this.additionalChildCount_; i++) { this.appendValueInput('DO' + i, Blockly.Arduino.ORDER_NONE); } } From 4e34c63f082dac6f1296051a707b7b92c5a316d8 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 11 Nov 2020 15:48:41 +0100 Subject: [PATCH 3/3] fix color in mutator --- src/components/Blockly/blocks/webserver.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Blockly/blocks/webserver.js b/src/components/Blockly/blocks/webserver.js index 049bfd9..da39df0 100644 --- a/src/components/Blockly/blocks/webserver.js +++ b/src/components/Blockly/blocks/webserver.js @@ -291,7 +291,7 @@ Blockly.Blocks['sensebox_general_html_tag'] = { Blockly.Blocks['first_child'] = { init: function () { - this.setColour(Blockly.Blocks.logic.HUE); + this.setColour(getColour().webserver); this.appendDummyInput() .appendField(""); this.setNextStatement(true); @@ -304,7 +304,7 @@ Blockly.Blocks['first_child'] = { Blockly.Blocks['additional_child'] = { init: function () { - this.setColour(Blockly.Blocks.logic.HUE); + this.setColour(getColour().webserver); this.appendDummyInput() .appendField(""); this.setPreviousStatement(true);