diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-dateoffsets.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-dateoffsets.js index 5f9b6331ac..57a729ca4c 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-dateoffsets.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-dateoffsets.js @@ -212,6 +212,8 @@ export default function (f7) { this.setOutput(true, 'ZonedDateTime') this.setColour(70) let tooltip = 'Parses a text into a ZonedDateTime supporting the following formats detected:\n' + + 'HH:mm\n' + + 'HH:mm:ss\n' + 'yyyy-MM-dd\n' + 'yyyy-MM-ddTHH:mm\n' + 'yyyy-MM-ddTHH:mm:ss\n' + diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-items.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-items.js index 67c203b671..f01bc98df9 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-items.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-items.js @@ -27,7 +27,7 @@ export default function (f7) { return [code, 0] } - /* get item structures */ + /* retrieve members of a group */ Blockly.Blocks['oh_groupmembers'] = { init: function () { this.appendValueInput('groupName') @@ -48,6 +48,35 @@ export default function (f7) { return [code, 0] } + /* retrieve items via their tags */ + Blockly.Blocks['oh_taggeditems'] = { + init: function () { + this.appendValueInput('tagName') + .appendField('get items with tag') + .setCheck('String') + this.setInputsInline(false) + this.setOutput(true, 'Array') + this.setColour(0) + this.setTooltip('Retrieve the items that have all the given tags') + this.setHelpUrl('https://www.openhab.org/docs/configuration/blockly/rules-blockly-items-things.html#get-tagged-items') + this.setOutput(true, null) + } + } + + Blockly.JavaScript['oh_taggeditems'] = function (block) { + let tagNames = Blockly.JavaScript.valueToCode(block, 'tagName', Blockly.JavaScript.ORDER_ATOMIC) + tagNames = tagNames.split(',') + let tags = '' + for (let i = 0; i < tagNames.length; i++) { + if (i > 0) { + tags += '\',\'' + } + tags += tagNames[i] + } + let code = `Java.from(itemRegistry.getItemsByTag(${tags}))` + return [code, 0] + } + Blockly.Blocks['oh_getitem'] = { init: function () { this.appendValueInput('itemName') diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-list.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-list.js new file mode 100644 index 0000000000..15733020b8 --- /dev/null +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-list.js @@ -0,0 +1,33 @@ +/* +* Adds new blocks to the list section +*/ +import Blockly from 'blockly' +export default function (f7) { + /* + * allows the concatenate a list into a new list + * Block + */ + Blockly.Blocks['oh_list_concatenate'] = { + init: function () { + this.appendValueInput('list1') + .appendField('concatenate') + .setCheck('Array') + this.appendValueInput('list2') + .appendField('to') + .setAlign(Blockly.ALIGN_RIGHT) + .setCheck('Array') + this.setInputsInline(true) + this.setOutput(true, 'Array') + this.setColour('%{BKY_LISTS_HUE}') + this.setTooltip('concatenate two arrays returning a new array') + this.setHelpUrl('https://www.openhab.org/docs/configuration/blockly/rules-blockly-standard-ext.html#concatenate-list') + } + } + + Blockly.JavaScript['oh_list_concatenate'] = function (block) { + const list1 = Blockly.JavaScript.valueToCode(block, 'list1', Blockly.JavaScript.ORDER_ATOMIC) + const list2 = Blockly.JavaScript.valueToCode(block, 'list2', Blockly.JavaScript.ORDER_ATOMIC) + const code = list1 + '.concat(' + list2 + ');\n' + return [code, 0] + } +} diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-persistence.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-persistence.js index 684d03b413..d4fb784461 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-persistence.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-persistence.js @@ -16,21 +16,21 @@ export default function defineOHBlocks_Persistence (f7) { .appendField(new Blockly.FieldDropdown([ ['average', 'averageSince'], ['delta', 'deltaSince'], ['deviation', 'deviationSince'], ['variance', 'varianceSince'], ['evolution rate', 'evolutionRate'], - ['minimum', 'minimumSince'], ['maximum', 'maximumSince'], ['sum', 'sumSince'] - ] + ['minimum', 'minimumSince'], ['maximum', 'maximumSince'], ['sum', 'sumSince'], + ['previous state value', 'previousState'], ['previous state value time', 'previousStateTime'] + ], this.handleTypeSelection.bind(this) ), 'methodName') + this.methodName = this.getFieldValue('methodName') this.appendValueInput('itemName') - .appendField('of the state of item') + .appendField('of the state of item named ') .setAlign(Blockly.ALIGN_RIGHT) - .setCheck('oh_itemtype') - this.appendValueInput('dayInfo') - .appendField('since') - .setAlign(Blockly.ALIGN_RIGHT) - .setCheck(['ZonedDateTime']) + .setCheck('String', 'oh_item') + this.updateShape() this.setInputsInline(false) this.setOutput(true, null) this.setColour(0) let thisBlock = this + this.setTooltip(function () { let methodName = thisBlock.getFieldValue('methodName') let TIP = { @@ -41,11 +41,42 @@ export default function defineOHBlocks_Persistence (f7) { 'evolutionRate': 'Gets the evolution rate of the state of a given Item since a certain point in time', 'minimumSince': 'Gets the minimum value of the State of a persisted Item since a certain point in time', 'maximumSince': 'Gets the maximum value of the State of a persisted Item since a certain point in time', - 'sumSince': 'Gets the sum of the previous States of a persisted Item since a certain point in time' + 'sumSince': 'Gets the sum of the previous States of a persisted Item since a certain point in time', + 'previousState': 'Gets the previous state with option to skip to different value as current', + 'previousStateTime': 'Gets the time when previous state last occurred with option to skip to different value as current' } return TIP[methodName] }) this.setHelpUrl('https://www.openhab.org/docs/configuration/blockly/rules-blockly-persistence.html#get-statistical-value-of-an-item') + }, + handleTypeSelection: function (methodName) { + if (this.methodName !== methodName) { + this.methodName = methodName + this.updateShape() + } + }, + updateShape: function () { + if (this.methodName === 'previousState' || this.methodName === 'previousStateTime') { + if (this.getInput('dayInfo')) { + this.removeInput('dayInfo') + } + if (!this.getInput('skipPrevious')) { + this.appendValueInput('skipPrevious') + .appendField('skip same ') + .setAlign(Blockly.ALIGN_RIGHT) + .setCheck(['Boolean']) + } + } else { + if (this.getInput('skipPrevious')) { + this.removeInput('skipPrevious') + } + if (!this.getInput('dayInfo')) { + this.appendValueInput('dayInfo') + .appendField('since') + .setAlign(Blockly.ALIGN_RIGHT) + .setCheck(['ZonedDateTime']) + } + } } } @@ -59,12 +90,32 @@ export default function defineOHBlocks_Persistence (f7) { const itemName = Blockly.JavaScript.valueToCode(block, 'itemName', Blockly.JavaScript.ORDER_ATOMIC) const methodName = block.getFieldValue('methodName') - const dayInfo = Blockly.JavaScript.valueToCode(block, 'dayInfo', Blockly.JavaScript.ORDER_NONE) + let code = '' - if (methodName === 'maximumSince' || methodName === 'minimumSince') { - code = `${persistence}.${methodName}(itemRegistry.getItem(${itemName}), ${dayInfo}).getState()` - } else { - code = `${persistence}.${methodName}(itemRegistry.getItem(${itemName}), ${dayInfo})` + let dayInfo = '' + + switch (methodName) { + case 'maximumSince': + case 'minimumSince': + dayInfo = Blockly.JavaScript.valueToCode(block, 'dayInfo', Blockly.JavaScript.ORDER_NONE) + code = `${persistence}.${methodName}(itemRegistry.getItem(${itemName}), ${dayInfo}).getState()` + break + + case 'previousState': + case 'previousStateTime': + let skipPrevious = Blockly.JavaScript.valueToCode(block, 'skipPrevious', Blockly.JavaScript.ORDER_NONE) + skipPrevious = ((skipPrevious === 'undefined') ? false : skipPrevious) + if (methodName === 'previousState') { + code = `((${persistence}.previousState(itemRegistry.getItem(${itemName}),${skipPrevious})) ? ${persistence}.previousState(itemRegistry.getItem(${itemName}),${skipPrevious}).getState(): 'undefined')` + } else if (methodName === 'previousStateTime') { + code = `((${persistence}.previousState(itemRegistry.getItem(${itemName}),${skipPrevious})) ? ${persistence}.previousState(itemRegistry.getItem(${itemName}),${skipPrevious}).getTimestamp() : 'undefined')` + } + break + + default: + dayInfo = Blockly.JavaScript.valueToCode(block, 'dayInfo', Blockly.JavaScript.ORDER_NONE) + code = `${persistence}.${methodName}(itemRegistry.getItem(${itemName}), ${dayInfo})` + break } return [code, Blockly.JavaScript.ORDER_NONE] diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-scripts.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-scripts.js index 818e043804..1792a08e7d 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-scripts.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-scripts.js @@ -105,7 +105,6 @@ export default function defineOHBlocks_Scripts (f7, scripts) { this.appendValueInput('function') .appendField('apply') .appendField(new Blockly.FieldTextInput('MAP'), 'type') - // .appendField(new Blockly.FieldDropdown([['MAP', 'MAP'], ['REGEX', 'REGEX'], ['JSONPATH', 'JSONPATH']]), 'type') .appendField('with') this.setInputsInline(false) @@ -128,7 +127,7 @@ export default function defineOHBlocks_Scripts (f7, scripts) { }) this.setHelpUrl(function () { const type = thisBlock.getFieldValue('type') - return 'https://www.openhab.org/addons/transformations/' + type.toLowerCase() + '/' + return 'https://www.openhab.org/docs/configuration/blockly/rules-blockly-run-and-process.html#transform-values-via-map-regex-or-jsonpath-and-others' + type.toLowerCase() + '/' }) } } diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-text.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-text.js index eb2beffb47..2aeb2b2faf 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-text.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/blocks-text.js @@ -15,7 +15,7 @@ export default function (f7) { this.appendDummyInput() .appendField('CRLF') this.setOutput(true, 'String') - this.setColour(160) + this.setColour('%{BKY_TEXTS_HUE}') this.setTooltip('Returns a carriage return line feed (\\r\\n).') this.setHelpUrl('https://www.openhab.org/docs/configuration/blockly/') } @@ -25,4 +25,37 @@ export default function (f7) { let code = '\'\\r\\n\'' return [code, Blockly.JavaScript.ORDER_NONE] } + + /* + * allows to replace a string + * Block + */ + Blockly.Blocks['oh_text_replace'] = { + init: function () { + this.appendValueInput('pattern') + .appendField('replace') + .setCheck('String') + this.appendValueInput('replacement') + .appendField('with') + .setAlign(Blockly.ALIGN_RIGHT) + .setCheck('String') + this.appendValueInput('origin') + .appendField('in') + .setAlign(Blockly.ALIGN_RIGHT) + .setCheck('String') + this.setInputsInline(true) + this.setOutput(true, 'String') + this.setColour('%{BKY_TEXTS_HUE}') + this.setTooltip('returns a new string with one, some, or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegEx. If it is a string, all occurences are replaced.') + this.setHelpUrl('https://www.openhab.org/docs/configuration/blockly/rules-blockly-standard-ext.html#concatenate-list') + } + } + + Blockly.JavaScript['oh_text_replace'] = function (block) { + const pattern = Blockly.JavaScript.valueToCode(block, 'pattern', Blockly.JavaScript.ORDER_ATOMIC) + const replacement = Blockly.JavaScript.valueToCode(block, 'replacement', Blockly.JavaScript.ORDER_ATOMIC) + const originText = Blockly.JavaScript.valueToCode(block, 'origin', Blockly.JavaScript.ORDER_ATOMIC) + const code = originText + '.replaceAll(' + pattern + ',' + replacement + ')' + return [code, 0] + } } diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/index.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/index.js index 62e504c497..9d0b68dea5 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/index.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/index.js @@ -13,6 +13,7 @@ import defineScriptsBlocks from './blocks-scripts' import definePersistenceBlocks from './blocks-persistence' import defineColorBlocks from './blocks-color' import defineTextBlocks from './blocks-text' +import defineListBlocks from './blocks-list' import { defineLibraries } from './libraries' @@ -34,5 +35,6 @@ export default function (f7, libraryDefinitions, data) { definePersistenceBlocks(f7) defineColorBlocks(f7) defineTextBlocks(f7) + defineListBlocks(f7) defineLibraries(libraryDefinitions) } diff --git a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/utils.js b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/utils.js index ffc8e87b72..92f6ef282a 100644 --- a/bundles/org.openhab.ui/web/src/assets/definitions/blockly/utils.js +++ b/bundles/org.openhab.ui/web/src/assets/definitions/blockly/utils.js @@ -46,6 +46,8 @@ export function addDateSupport () { 'getZonedDateTime', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(datetime) {', ' datetime = String(datetime).replace(\'T\', \' \')', + ' var regex_time_min = /^\\d{2}:\\d{2}$/;', + ' var regex_time_sec = /^\\d{2}:\\d{2}:\\d{2}$/;', ' var regex_date = /^\\d{4}-\\d{2}-\\d{2}$/;', ' var regex_date_time_min = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$/;', ' var regex_date_time_sec = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/;', @@ -55,7 +57,16 @@ export function addDateSupport () { ' var regex_date_time_ms_tz = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d{3}[+-]\\d{2}:\\d{2}$/;', ' var regex_date_time_us_tz = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d{6}[+-]\\d{2}:\\d{2}$/;', ' var regex_oh = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d{3}[+-]\\d{4}$/;', + ' var now = zdt.now();', + ' var now_year = now.getYear();', + ' var now_month = now.getMonthValue();', + ' var now_day = now.getDayOfMonth();', + ' var today = \'\' + now_year;', + ' today += \'-\' + (\'0\' + now_month).slice(-2);', + ' today += \'-\' + (\'0\' + now_day).slice(-2)+\' \';', ' switch (true) {', + ` case regex_time_min.test(datetime): return ${zdt}.parse(today + datetime + ':00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));`, + ` case regex_time_sec.test(datetime): return ${zdt}.parse(today + datetime + '+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));`, ` case regex_date.test(datetime): return ${zdt}.parse(datetime + ' 00:00:00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));`, ` case regex_date_time_min.test(datetime): return ${zdt}.parse(datetime + ':00+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));`, ` case regex_date_time_sec.test(datetime): return ${zdt}.parse(datetime + '+00:00', dtf.ofPattern('yyyy-MM-dd HH:mm:ssz'));`, diff --git a/bundles/org.openhab.ui/web/src/pages/settings/rules/script/blockly-editor.vue b/bundles/org.openhab.ui/web/src/pages/settings/rules/script/blockly-editor.vue index d485081edd..36f266d532 100644 --- a/bundles/org.openhab.ui/web/src/pages/settings/rules/script/blockly-editor.vue +++ b/bundles/org.openhab.ui/web/src/pages/settings/rules/script/blockly-editor.vue @@ -209,6 +209,23 @@ + + + + pattern + + + + + replacement + + + + + origin + + + @@ -221,6 +238,7 @@ + @@ -357,6 +375,11 @@ + + + + +