404
+ +Page not found
+ + +diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..ac17e62 --- /dev/null +++ b/404.html @@ -0,0 +1,117 @@ + + +
+ + + + +Page not found
+ + +In the nodes you can set a json object or msg object to dynamically select devices.
+You need to understand the JSON
format before using queries. A Json Array is
+not Json Object.
A query is made of one or more rule.
+The root condition of query is AND
, they need to match all rules of the query.
A rule have always a type
. The possibles values are basic
, match
. If the type
is ommited, and will be detected
+in this order:
device_type
, device_id
, device_path
or uniqueid
value is present it’s a basic
rule.match
value is present it’s a match
rule.If you want to set more than one rule you need to put them in an array. A device need to match all rules to be valid. If
+you want OR
condition check Sub Match.
[
+ {
+ "type": "match",
+ "match": {
+ "type": "Color light"
+ }
+ },
+ {
+ "type": "match",
+ "match": {
+ "state.on": true
+ }
+ }
+]
+
+In basic rule you can only use device_type
, device_id
, device_path
, uniqueid
to filter devices. They are faster
+than advanced queries.
To match this rule the device need to be a sensors
and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000
.
{
+ "type": "basic",
+ "device_type": "sensors",
+ "uniqueid": "00:11:22:33:44:55:66:77-01-1000"
+}
+
+The device_type
can be omitted but in rare cases there can be multiple devices with the same uniqueid
.
+See #77.
{
+ "uniqueid": "00:11:22:33:44:55:66:77-01-1000"
+}
+
+To match this rule the device, need to be a sensors
and have his id set to 1. This is not recommended because the id
+can change.
{
+ "device_type": "sensors",
+ "device_id": 1
+}
+
+To match this rule the device, need to be a sensors
and have his id set to 1. This is not recommended because the id
+can change.
{
+ "device_path": "sensors/device_id/1"
+}
+
+To match this rule the device need to be a sensors
and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000
.
{
+ "device_path": "sensors/uniqueid/00:11:22:33:44:55:66:77-01-1000"
+}
+
+For all other params you need to use an advanced query.
+An advanced rule is made of one or more comparaison.
+{
+ "type": "match",
+ "match": {
+ "type": "Color light"
+ }
+}
+
+A field name can have a dot notation to go deeper inside data like state.on
. If the key contain the dot character you
+need to escape it like this : name\\.lastname
. Currently you can do deeper inside an array but that
+my change later.
See also Sub Match.
+type
is match
.inverted
can be true
or false
the result of the rule will be inverted.method
can be AND
or OR
. The method value is not case sensitive.&&
and ||
are also valid.AND
) the condition listed in match
or at least one (OR
).AND
.match
rule is a object of key-value rules to match the device data.boolean
, number
or string
.boolean
, number
or string
.state.on
.boolean
, number
, string
or object
+ for Complex comparaison.match
is equal to true
all device will be matched.match
is equal to false
or undefined
none device will be matched.{
+ "match": {
+ "state.on": true,
+ "state.alert": "none",
+ "mode": 3,
+ "type": ["Color temperature light", "Color light"]
+ }
+}
+
+Same query with all options;
+{
+ "type": "match",
+ "method": "AND",
+ "match": {
+ "state.on": true,
+ "state.alert": "none",
+ "mode": 3,
+ "type": ["Color temperature light", "Color light"]
+ }
+}
+
+You can set a more advanced comparaison using an object.
+For all object comparaison the type
can be ommited, and will be detected in this order:
value
value is present it’s a complex
comparaison.after
or before
value is present it’s a date
comparaison.regex
value is present it’s a regex
comparaison.version
value is present it’s a version
comparaison.For example if you set a regex
and version
values, only the regex
will be used.
+In case you want to set multiple comparaison on the same value define an array of objects.
In case strict compare is not for you, you can define more customizable comparaison.
+type
always complex
.convertTo
a value type to convert the value, can be boolean
, number
, string
, date
. By default do not
+ convert.convertLeft
boolean, if you want to convert the device value. By default : true.convertRight
boolean, if you want to convert the query value. By default : false.operator
the operator, can be ===
, !==
, ==
, !=
, >
, >=
, <
, <=
. By default : ==
.strict
do the comparaison is strict, if yes the value types need be the same, can be true
or false
. By
+ default : false
.value
a value to compare to, can be boolean
, number
, string
, date
. It’s can also be an array
of values,
+ see notes.The comparaison is done in the order device
operator
value
. Ex : ctmax > 65000
;
convertTo
will used on left side by default. Check convertLeft
and convertRight
.convertTo
date
will use the method Date.parse.==
and !=
because this may cause
+ unexpected type coercion.operator
===
and !==
are always strict.true
at least one time.{
+ "match": {
+ "type": "Color temperature light",
+ "ctmax": {
+ "convertTo": "number",
+ "convertRight": true,
+ "operator": ">",
+ "value": "65000"
+ }
+ }
+}
+
+You can define a special comparaison that compare only dates.
+type
always date
.after
the device value should be after or equal to the date set.before
the device value should be before or equal to the date set.timestamp
from an node-red’s input
+ node.{
+ "match": {
+ "state.lastupdated": {
+ "type": "date",
+ "after": "1969-07-21T02:56Z",
+ "before": "1972-12-14T12:00Z"
+ }
+ }
+}
+
+Or with JSONata expression: Ex not updated in the last hour.
+{
+ "match":{
+ "state.lastupdated":{
+ "type":"date",
+ "before":$millis()-60*60*1000
+ }
+ }
+}
+
+The regex will be compared to the device value with match method.
+type
always regex
.regex
can be any value accepted
+ by RegExp constructor.regex
needs to be a string
otherwise it’s will never match.""
) it’s will always match.^
and $
if you want to match the complete value.flag
will be the second argument
+ of RegExp constructor. By default ‘g’.{
+ "match": {
+ "state.on": false,
+ "modelid": {
+ "type": "regex",
+ "regex": "^(.*)bulb E27(.*)$",
+ "flag": "g"
+ }
+ }
+}
+
+You can define a special comparaison that compare only semver versions.
+This method will use the method compare-versions.
type
always version
.operator
the operator, can be ===
, !==
, ==
, !=
, >
, >=
, <
, <=
. By default : ‘>=’.version
a semver version to compare to.123456
because it’s superior to 2.0.0
.Example : get all device with swversion
superior or equal to 2.0.0
{
+ "match": {
+ "type": "Color temperature light",
+ "swversion": {
+ "type": "version",
+ "operator": ">=",
+ "version": "2.0.0"
+ }
+ }
+}
+
+For now you can’t make query on devices values that is array like devicemembership
.
+See #172.
In case you want to do more rules inside a rule you can use an array to define a list of rules instead of a pair key
+value to check.
+To avoid infinite loops the depth is limited to 10 and will not match any devices if he reaches this limit.
{
+ "method": "OR",
+ "match": [
+ {
+ "method": "OR",
+ "match": {
+ "state.on": true,
+ "colorcapabilities": 0
+ }
+ },
+ {
+ "match": {
+ "type": "Color temperature light",
+ "swversion": "2.0.029"
+ }
+ }
+ ]
+}
+
+This will result to this code in javascript.
+let result =
+ device.state.on === true ||
+ device.colorcapabilities === 0 ||
+ (device.type === "Color temperature light" && device.swversion === "2.0.029");
+
+:warning: You cannot mix rules and pair key-value inside the same match definition. It’s also not a valid json format.
+ + +{
+ "method": "OR",
+ "match": [
+ "hascolor": true,
+ {
+ "match": {
+ "type": "Color temperature light",
+ "colorcapabilities": 8
+ }
+ }
+ ]
+}
+
+
+
+Theses query will not match any devices.
+{}
+
+{
+ "match": false
+}
+
+This query will match all devices.
+{
+ "match": true
+}
+
+
+ This documentation describes the Node-Red plugin for deCONZ.
+ +On the input and get nodes you can have different payload format for the outputs. There are multiple kinds of settings +for the data format, the type, the device format and the payload format.
+The message will contain multiple properties.
+The payload as selected in the payload setting. It’s could be a simple value or an object with key value.
+The value set inside the node configuration.
+Contain what is send inside the payload. Can be complete
if the payload contains all attributes of the device or
+one of the keys of the value. Ex : buttonevent
Contain the raw data sent by deconz that lead to this msg.
+Contain the count of devices used to calculate the value for the given attribute.
+All attributes of the device that send data
+Contain an array of all values changed since last time in dot notation. Ex : state.lastupdated
The payload format value can be either Complete payload, Each payload or a list of selected value. Be careful, you will
+get a message per selected value. If you want to have multiple value inside a message just select Complete payload
.
The device format set if the data should be sent one message per device, or one message with all device, or apply some +math on the values.
+The node will send a message per device that send data.
+The node will send a message with all payload inside an array. The message will contain a payload that is an array of
+single message. Ex msg.payload[0].payload
is the payload of the first device. Each element will contain only the
+properties payload, meta, meta_changed. The properties topic
, payload_format
, payload_raw
will be on the msg directly.
Where is specials format that do simple maths on values. The result will be inside the payload with the same structure
+as the initial payload. Only numeric values are kept, the values like "1234"
are string and not numeric. The meta
+property will be always an array with all devices. If some devices don’t have all properties the missing one will be
+skipped for devices that don’t have it.
For examples below the data are:
+Device x
+{
+ "lastupdated": "2021-09-06T15:39:13.168",
+ "temperature": 2500
+}
+
+Device y
+{
+ "lastupdated": "2021-09-06T15:39:13.168",
+ "temperature": 3000
+}
+
+Device z
+{
+ "lastupdated": "2021-09-06T15:39:13.168",
+ " humidity": 5570
+}
+
+All properties of the devices will be added individually.
+Example results
+{
+ "temperature": 5500,
+ "humidity": 5570
+}
+
+I know adding temperature don’t make sense but could be useful for power usage.
+All properties of the devices will be added recursively and then divided by the amount of device that have that +property.
+Example results
+{
+ "temperature": 2750,
+ "humidity": 5570
+}
+
+The result will be a set of minimal value of each property. Example results
+{
+ "temperature": 2500,
+ "humidity": 5570
+}
+
+The result will be a set of maximal value of each property. Example results
+{
+ "temperature": 3000,
+ "humidity": 5570
+}
+
+
+ ' + escapeHtml(summary) +'
' + noResultsText + '
'); + } +} + +function doSearch () { + var query = document.getElementById('mkdocs-search-query').value; + if (query.length > min_search_length) { + if (!window.Worker) { + displayResults(search(query)); + } else { + searchWorker.postMessage({query: query}); + } + } else { + // Clear results for short queries + displayResults([]); + } +} + +function initSearch () { + var search_input = document.getElementById('mkdocs-search-query'); + if (search_input) { + search_input.addEventListener("keyup", doSearch); + } + var term = getSearchTermFromLocation(); + if (term) { + search_input.value = term; + doSearch(); + } +} + +function onWorkerMessage (e) { + if (e.data.allowSearch) { + initSearch(); + } else if (e.data.results) { + var results = e.data.results; + displayResults(results); + } else if (e.data.config) { + min_search_length = e.data.config.min_search_length-1; + } +} + +if (!window.Worker) { + console.log('Web Worker API not supported'); + // load index in main thread + $.getScript(joinUrl(base_url, "search/worker.js")).done(function () { + console.log('Loaded worker'); + init(); + window.postMessage = function (msg) { + onWorkerMessage({data: msg}); + }; + }).fail(function (jqxhr, settings, exception) { + console.error('Could not load worker.js'); + }); +} else { + // Wrap search in a web worker + var searchWorker = new Worker(joinUrl(base_url, "search/worker.js")); + searchWorker.postMessage({init: true}); + searchWorker.onmessage = onWorkerMessage; +} diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..e22cae5 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Introduction \u00b6 This documentation describes the Node-Red plugin for deCONZ.","title":"Introduction"},{"location":"#introduction","text":"This documentation describes the Node-Red plugin for deCONZ.","title":"Introduction"},{"location":"device_queries/","text":"Device queries \u00b6 In the nodes you can set a json object or msg object to dynamically select devices. You need to understand the JSON format before using queries. A Json Array is not Json Object . A query is made of one or more rule. The root condition of query is AND , they need to match all rules of the query. Rules \u00b6 A rule have always a type . The possibles values are basic , match . If the type is ommited, and will be detected in this order: If a device_type , device_id , device_path or uniqueid value is present it\u2019s a basic rule. If a match value is present it\u2019s a match rule. If you want to set more than one rule you need to put them in an array. A device need to match all rules to be valid. If you want OR condition check Sub Match . [ { \"type\": \"match\", \"match\": { \"type\": \"Color light\" } }, { \"type\": \"match\", \"match\": { \"state.on\": true } } ] Basic rule \u00b6 In basic rule you can only use device_type , device_id , device_path , uniqueid to filter devices. They are faster than advanced queries. Get by unique id \u00b6 To match this rule the device need to be a sensors and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000 . { \"type\": \"basic\", \"device_type\": \"sensors\", \"uniqueid\": \"00:11:22:33:44:55:66:77-01-1000\" } The device_type can be omitted but in rare cases there can be multiple devices with the same uniqueid . See #77 . { \"uniqueid\": \"00:11:22:33:44:55:66:77-01-1000\" } Get by id \u00b6 To match this rule the device, need to be a sensors and have his id set to 1. This is not recommended because the id can change. { \"device_type\": \"sensors\", \"device_id\": 1 } Get by path \u00b6 To match this rule the device, need to be a sensors and have his id set to 1. This is not recommended because the id can change. { \"device_path\": \"sensors/device_id/1\" } To match this rule the device need to be a sensors and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000 . { \"device_path\": \"sensors/uniqueid/00:11:22:33:44:55:66:77-01-1000\" } Other params \u00b6 For all other params you need to use an advanced query. Advanced rules \u00b6 An advanced rule is made of one or more comparaison. { \"type\": \"match\", \"match\": { \"type\": \"Color light\" } } A field name can have a dot notation to go deeper inside data like state.on . If the key contain the dot character you need to escape it like this : name\\\\.lastname . Currently you can do deeper inside an array but that my change later. Rules \u00b6 Match rule \u00b6 See also Sub Match . type is match . inverted can be true or false the result of the rule will be inverted. method can be AND or OR . The method value is not case sensitive. The methods && and || are also valid. The rule need to match all ( AND ) the condition listed in match or at least one ( OR ). By default, the method is AND . match rule is a object of key-value rules to match the device data. A value can be a boolean , number or string . If the value is an array the value need to be strictly equal to one of the value. Theses values can only be boolean , number or string . It the value is an object it\u2019s a Complex comparaison . Note about match object \u00b6 The key can be a path like state.on . The value need to be Strict equality to be able to match. If the value is an array the device value needs to be equal to at least one of the values. The value can be an array of mixed types of boolean , number , string or object for Complex comparaison . If match is equal to true all device will be matched. If match is equal to false or undefined none device will be matched. Base format \u00b6 { \"match\": { \"state.on\": true, \"state.alert\": \"none\", \"mode\": 3, \"type\": [\"Color temperature light\", \"Color light\"] } } Same query with all options; { \"type\": \"match\", \"method\": \"AND\", \"match\": { \"state.on\": true, \"state.alert\": \"none\", \"mode\": 3, \"type\": [\"Color temperature light\", \"Color light\"] } } Object comparaison \u00b6 You can set a more advanced comparaison using an object. For all object comparaison the type can be ommited, and will be detected in this order: If a value value is present it\u2019s a complex comparaison. If a after or before value is present it\u2019s a date comparaison. If a regex value is present it\u2019s a regex comparaison. If a version value is present it\u2019s a version comparaison. For example if you set a regex and version values, only the regex will be used. In case you want to set multiple comparaison on the same value define an array of objects. Complex comparaison \u00b6 In case strict compare is not for you, you can define more customizable comparaison. type always complex . convertTo a value type to convert the value, can be boolean , number , string , date . By default do not convert. convertLeft boolean, if you want to convert the device value. By default : true. convertRight boolean, if you want to convert the query value. By default : false. operator the operator, can be === , !== , == , != , > , >= , < , <= . By default : == . strict do the comparaison is strict, if yes the value types need be the same, can be true or false . By default : false . value a value to compare to, can be boolean , number , string , date . It\u2019s can also be an array of values, see notes. The comparaison is done in the order device operator value . Ex : ctmax > 65000 ; Notes \u00b6 The convertTo will used on left side by default. Check convertLeft and convertRight . The convertTo date will use the method Date.parse. Try avoiding the operator == and != because this may cause unexpected type coercion . The operator === and !== are always strict. If the value is an array, each element of the array will converted and tested. To be matched the comparaisons need to be true at least one time. { \"match\": { \"type\": \"Color temperature light\", \"ctmax\": { \"convertTo\": \"number\", \"convertRight\": true, \"operator\": \">\", \"value\": \"65000\" } } } Date comparaison \u00b6 You can define a special comparaison that compare only dates. type always date . after the device value should be after or equal to the date set. before the device value should be before or equal to the date set. Notes \u00b6 One of the two date options can be omitted. If booth settings set, he need to match all. If none valid, he return always false. The value can be anything supported by Date.parse or a valid Unix timestamp *1000. It\u2019s a number representing the milliseconds elapsed since January 1, 1970, 00:00:00 UTC. It\u2019s also can be a value of type timestamp from an node-red\u2019s input node. If the value is set to undefined it\u2019s will be ignored. { \"match\": { \"state.lastupdated\": { \"type\": \"date\", \"after\": \"1969-07-21T02:56Z\", \"before\": \"1972-12-14T12:00Z\" } } } Or with JSONata expression: Ex not updated in the last hour. { \"match\":{ \"state.lastupdated\":{ \"type\":\"date\", \"before\":$millis()-60*60*1000 } } } Regex comparaison \u00b6 The regex will be compared to the device value with match method. type always regex . regex can be any value accepted by RegExp constructor . A regex needs to be a string otherwise it\u2019s will never match. If the value is empty ( \"\" ) it\u2019s will always match. Don\u2019t forget to put ^ and $ if you want to match the complete value. flag will be the second argument of RegExp constructor . By default \u2018g\u2019. { \"match\": { \"state.on\": false, \"modelid\": { \"type\": \"regex\", \"regex\": \"^(.*)bulb E27(.*)$\", \"flag\": \"g\" } } } Version comparaison \u00b6 You can define a special comparaison that compare only semver versions. This method will use the method compare-versions . type always version . operator the operator, can be === , !== , == , != , > , >= , < , <= . By default : \u2018>=\u2019. version a semver version to compare to. Notes \u00b6 If the version is not valid it\u2019s will always return false; Be carefull with big integer version like 123456 because it\u2019s superior to 2.0.0 . Example : get all device with swversion superior or equal to 2.0.0 { \"match\": { \"type\": \"Color temperature light\", \"swversion\": { \"type\": \"version\", \"operator\": \">=\", \"version\": \"2.0.0\" } } } Array comparaison \u00b6 For now you can\u2019t make query on devices values that is array like devicemembership . See #172 . Sub Match \u00b6 In case you want to do more rules inside a rule you can use an array to define a list of rules instead of a pair key value to check. To avoid infinite loops the depth is limited to 10 and will not match any devices if he reaches this limit. { \"method\": \"OR\", \"match\": [ { \"method\": \"OR\", \"match\": { \"state.on\": true, \"colorcapabilities\": 0 } }, { \"match\": { \"type\": \"Color temperature light\", \"swversion\": \"2.0.029\" } } ] } This will result to this code in javascript. let result = device.state.on === true || device.colorcapabilities === 0 || (device.type === \"Color temperature light\" && device.swversion === \"2.0.029\"); :warning: You cannot mix rules and pair key-value inside the same match definition. It\u2019s also not a valid json format. { \"method\": \"OR\", \"match\": [ \"hascolor\": true, { \"match\": { \"type\": \"Color temperature light\", \"colorcapabilities\": 8 } } ] } Special cases \u00b6 Empty queries \u00b6 Theses query will not match any devices. {} { \"match\": false } All device query \u00b6 This query will match all devices. { \"match\": true }","title":"Device Queries"},{"location":"device_queries/#device-queries","text":"In the nodes you can set a json object or msg object to dynamically select devices. You need to understand the JSON format before using queries. A Json Array is not Json Object . A query is made of one or more rule. The root condition of query is AND , they need to match all rules of the query.","title":"Device queries"},{"location":"device_queries/#rules","text":"A rule have always a type . The possibles values are basic , match . If the type is ommited, and will be detected in this order: If a device_type , device_id , device_path or uniqueid value is present it\u2019s a basic rule. If a match value is present it\u2019s a match rule. If you want to set more than one rule you need to put them in an array. A device need to match all rules to be valid. If you want OR condition check Sub Match . [ { \"type\": \"match\", \"match\": { \"type\": \"Color light\" } }, { \"type\": \"match\", \"match\": { \"state.on\": true } } ]","title":"Rules"},{"location":"device_queries/#basic-rule","text":"In basic rule you can only use device_type , device_id , device_path , uniqueid to filter devices. They are faster than advanced queries.","title":"Basic rule"},{"location":"device_queries/#get-by-unique-id","text":"To match this rule the device need to be a sensors and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000 . { \"type\": \"basic\", \"device_type\": \"sensors\", \"uniqueid\": \"00:11:22:33:44:55:66:77-01-1000\" } The device_type can be omitted but in rare cases there can be multiple devices with the same uniqueid . See #77 . { \"uniqueid\": \"00:11:22:33:44:55:66:77-01-1000\" }","title":"Get by unique id"},{"location":"device_queries/#get-by-id","text":"To match this rule the device, need to be a sensors and have his id set to 1. This is not recommended because the id can change. { \"device_type\": \"sensors\", \"device_id\": 1 }","title":"Get by id"},{"location":"device_queries/#get-by-path","text":"To match this rule the device, need to be a sensors and have his id set to 1. This is not recommended because the id can change. { \"device_path\": \"sensors/device_id/1\" } To match this rule the device need to be a sensors and have his uniqueid set to 00:11:22:33:44:55:66:77-01-1000 . { \"device_path\": \"sensors/uniqueid/00:11:22:33:44:55:66:77-01-1000\" }","title":"Get by path"},{"location":"device_queries/#other-params","text":"For all other params you need to use an advanced query.","title":"Other params"},{"location":"device_queries/#advanced-rules","text":"An advanced rule is made of one or more comparaison. { \"type\": \"match\", \"match\": { \"type\": \"Color light\" } } A field name can have a dot notation to go deeper inside data like state.on . If the key contain the dot character you need to escape it like this : name\\\\.lastname . Currently you can do deeper inside an array but that my change later.","title":"Advanced rules"},{"location":"device_queries/#rules_1","text":"","title":"Rules"},{"location":"device_queries/#match-rule","text":"See also Sub Match . type is match . inverted can be true or false the result of the rule will be inverted. method can be AND or OR . The method value is not case sensitive. The methods && and || are also valid. The rule need to match all ( AND ) the condition listed in match or at least one ( OR ). By default, the method is AND . match rule is a object of key-value rules to match the device data. A value can be a boolean , number or string . If the value is an array the value need to be strictly equal to one of the value. Theses values can only be boolean , number or string . It the value is an object it\u2019s a Complex comparaison .","title":"Match rule"},{"location":"device_queries/#note-about-match-object","text":"The key can be a path like state.on . The value need to be Strict equality to be able to match. If the value is an array the device value needs to be equal to at least one of the values. The value can be an array of mixed types of boolean , number , string or object for Complex comparaison . If match is equal to true all device will be matched. If match is equal to false or undefined none device will be matched.","title":"Note about match object"},{"location":"device_queries/#base-format","text":"{ \"match\": { \"state.on\": true, \"state.alert\": \"none\", \"mode\": 3, \"type\": [\"Color temperature light\", \"Color light\"] } } Same query with all options; { \"type\": \"match\", \"method\": \"AND\", \"match\": { \"state.on\": true, \"state.alert\": \"none\", \"mode\": 3, \"type\": [\"Color temperature light\", \"Color light\"] } }","title":"Base format"},{"location":"device_queries/#object-comparaison","text":"You can set a more advanced comparaison using an object. For all object comparaison the type can be ommited, and will be detected in this order: If a value value is present it\u2019s a complex comparaison. If a after or before value is present it\u2019s a date comparaison. If a regex value is present it\u2019s a regex comparaison. If a version value is present it\u2019s a version comparaison. For example if you set a regex and version values, only the regex will be used. In case you want to set multiple comparaison on the same value define an array of objects.","title":"Object comparaison"},{"location":"device_queries/#complex-comparaison","text":"In case strict compare is not for you, you can define more customizable comparaison. type always complex . convertTo a value type to convert the value, can be boolean , number , string , date . By default do not convert. convertLeft boolean, if you want to convert the device value. By default : true. convertRight boolean, if you want to convert the query value. By default : false. operator the operator, can be === , !== , == , != , > , >= , < , <= . By default : == . strict do the comparaison is strict, if yes the value types need be the same, can be true or false . By default : false . value a value to compare to, can be boolean , number , string , date . It\u2019s can also be an array of values, see notes. The comparaison is done in the order device operator value . Ex : ctmax > 65000 ;","title":"Complex comparaison"},{"location":"device_queries/#notes","text":"The convertTo will used on left side by default. Check convertLeft and convertRight . The convertTo date will use the method Date.parse. Try avoiding the operator == and != because this may cause unexpected type coercion . The operator === and !== are always strict. If the value is an array, each element of the array will converted and tested. To be matched the comparaisons need to be true at least one time. { \"match\": { \"type\": \"Color temperature light\", \"ctmax\": { \"convertTo\": \"number\", \"convertRight\": true, \"operator\": \">\", \"value\": \"65000\" } } }","title":"Notes"},{"location":"device_queries/#date-comparaison","text":"You can define a special comparaison that compare only dates. type always date . after the device value should be after or equal to the date set. before the device value should be before or equal to the date set.","title":"Date comparaison"},{"location":"device_queries/#notes_1","text":"One of the two date options can be omitted. If booth settings set, he need to match all. If none valid, he return always false. The value can be anything supported by Date.parse or a valid Unix timestamp *1000. It\u2019s a number representing the milliseconds elapsed since January 1, 1970, 00:00:00 UTC. It\u2019s also can be a value of type timestamp from an node-red\u2019s input node. If the value is set to undefined it\u2019s will be ignored. { \"match\": { \"state.lastupdated\": { \"type\": \"date\", \"after\": \"1969-07-21T02:56Z\", \"before\": \"1972-12-14T12:00Z\" } } } Or with JSONata expression: Ex not updated in the last hour. { \"match\":{ \"state.lastupdated\":{ \"type\":\"date\", \"before\":$millis()-60*60*1000 } } }","title":"Notes"},{"location":"device_queries/#regex-comparaison","text":"The regex will be compared to the device value with match method. type always regex . regex can be any value accepted by RegExp constructor . A regex needs to be a string otherwise it\u2019s will never match. If the value is empty ( \"\" ) it\u2019s will always match. Don\u2019t forget to put ^ and $ if you want to match the complete value. flag will be the second argument of RegExp constructor . By default \u2018g\u2019. { \"match\": { \"state.on\": false, \"modelid\": { \"type\": \"regex\", \"regex\": \"^(.*)bulb E27(.*)$\", \"flag\": \"g\" } } }","title":"Regex comparaison"},{"location":"device_queries/#version-comparaison","text":"You can define a special comparaison that compare only semver versions. This method will use the method compare-versions . type always version . operator the operator, can be === , !== , == , != , > , >= , < , <= . By default : \u2018>=\u2019. version a semver version to compare to.","title":"Version comparaison"},{"location":"device_queries/#notes_2","text":"If the version is not valid it\u2019s will always return false; Be carefull with big integer version like 123456 because it\u2019s superior to 2.0.0 . Example : get all device with swversion superior or equal to 2.0.0 { \"match\": { \"type\": \"Color temperature light\", \"swversion\": { \"type\": \"version\", \"operator\": \">=\", \"version\": \"2.0.0\" } } }","title":"Notes"},{"location":"device_queries/#array-comparaison","text":"For now you can\u2019t make query on devices values that is array like devicemembership . See #172 .","title":"Array comparaison"},{"location":"device_queries/#sub-match","text":"In case you want to do more rules inside a rule you can use an array to define a list of rules instead of a pair key value to check. To avoid infinite loops the depth is limited to 10 and will not match any devices if he reaches this limit. { \"method\": \"OR\", \"match\": [ { \"method\": \"OR\", \"match\": { \"state.on\": true, \"colorcapabilities\": 0 } }, { \"match\": { \"type\": \"Color temperature light\", \"swversion\": \"2.0.029\" } } ] } This will result to this code in javascript. let result = device.state.on === true || device.colorcapabilities === 0 || (device.type === \"Color temperature light\" && device.swversion === \"2.0.029\"); :warning: You cannot mix rules and pair key-value inside the same match definition. It\u2019s also not a valid json format. { \"method\": \"OR\", \"match\": [ \"hascolor\": true, { \"match\": { \"type\": \"Color temperature light\", \"colorcapabilities\": 8 } } ] }","title":"Sub Match"},{"location":"device_queries/#special-cases","text":"","title":"Special cases"},{"location":"device_queries/#empty-queries","text":"Theses query will not match any devices. {} { \"match\": false }","title":"Empty queries"},{"location":"device_queries/#all-device-query","text":"This query will match all devices. { \"match\": true }","title":"All device query"},{"location":"msg_format/","text":"Msg Format \u00b6 On the input and get nodes you can have different payload format for the outputs. There are multiple kinds of settings for the data format, the type, the device format and the payload format. Basic format example \u00b6 The message will contain multiple properties. payload \u00b6 The payload as selected in the payload setting. It\u2019s could be a simple value or an object with key value. topic \u00b6 The value set inside the node configuration. payload_format :new: \u00b6 Contain what is send inside the payload. Can be complete if the payload contains all attributes of the device or one of the keys of the value. Ex : buttonevent payload_raw (Only for input node) \u00b6 Contain the raw data sent by deconz that lead to this msg. payload_count (Only for get node with maths format) :new: \u00b6 Contain the count of devices used to calculate the value for the given attribute. meta \u00b6 All attributes of the device that send data meta_changed :new: \u00b6 Contain an array of all values changed since last time in dot notation. Ex : state.lastupdated Payload format \u00b6 The payload format value can be either Complete payload, Each payload or a list of selected value. Be careful, you will get a message per selected value. If you want to have multiple value inside a message just select Complete payload . Device format \u00b6 The device format set if the data should be sent one message per device, or one message with all device, or apply some math on the values. Single x \u2026 y \u2026 z \u00b6 The node will send a message per device that send data. Array [x,y,z] \u00b6 The node will send a message with all payload inside an array. The message will contain a payload that is an array of single message. Ex msg.payload[0].payload is the payload of the first device. Each element will contain only the properties payload, meta, meta_changed. The properties topic , payload_format , payload_raw will be on the msg directly. Maths formats \u00b6 Where is specials format that do simple maths on values. The result will be inside the payload with the same structure as the initial payload. Only numeric values are kept, the values like \"1234\" are string and not numeric. The meta property will be always an array with all devices. If some devices don\u2019t have all properties the missing one will be skipped for devices that don\u2019t have it. For examples below the data are: Device x { \"lastupdated\": \"2021-09-06T15:39:13.168\", \"temperature\": 2500 } Device y { \"lastupdated\": \"2021-09-06T15:39:13.168\", \"temperature\": 3000 } Device z { \"lastupdated\": \"2021-09-06T15:39:13.168\", \" humidity\": 5570 } Sum (x+y+z) \u00b6 All properties of the devices will be added individually. Example results { \"temperature\": 5500, \"humidity\": 5570 } I know adding temperature don\u2019t make sense but could be useful for power usage. Average (x+y+z)/3 \u00b6 All properties of the devices will be added recursively and then divided by the amount of device that have that property. Example results { \"temperature\": 2750, \"humidity\": 5570 } Min X+y+Z = y \u00b6 The result will be a set of minimal value of each property. Example results { \"temperature\": 2500, \"humidity\": 5570 } Max X + y + z = X \u00b6 The result will be a set of maximal value of each property. Example results { \"temperature\": 3000, \"humidity\": 5570 }","title":"Msg Format"},{"location":"msg_format/#msg-format","text":"On the input and get nodes you can have different payload format for the outputs. There are multiple kinds of settings for the data format, the type, the device format and the payload format.","title":"Msg Format"},{"location":"msg_format/#basic-format-example","text":"The message will contain multiple properties.","title":"Basic format example"},{"location":"msg_format/#payload","text":"The payload as selected in the payload setting. It\u2019s could be a simple value or an object with key value.","title":"payload"},{"location":"msg_format/#topic","text":"The value set inside the node configuration.","title":"topic"},{"location":"msg_format/#payload_format-new","text":"Contain what is send inside the payload. Can be complete if the payload contains all attributes of the device or one of the keys of the value. Ex : buttonevent","title":"payload_format :new:"},{"location":"msg_format/#payload_raw-only-for-input-node","text":"Contain the raw data sent by deconz that lead to this msg.","title":"payload_raw (Only for input node)"},{"location":"msg_format/#payload_count-only-for-get-node-with-maths-format-new","text":"Contain the count of devices used to calculate the value for the given attribute.","title":"payload_count (Only for get node with maths format) :new:"},{"location":"msg_format/#meta","text":"All attributes of the device that send data","title":"meta"},{"location":"msg_format/#meta_changed-new","text":"Contain an array of all values changed since last time in dot notation. Ex : state.lastupdated","title":"meta_changed :new:"},{"location":"msg_format/#payload-format","text":"The payload format value can be either Complete payload, Each payload or a list of selected value. Be careful, you will get a message per selected value. If you want to have multiple value inside a message just select Complete payload .","title":"Payload format"},{"location":"msg_format/#device-format","text":"The device format set if the data should be sent one message per device, or one message with all device, or apply some math on the values.","title":"Device format"},{"location":"msg_format/#single-x-y-z","text":"The node will send a message per device that send data.","title":"Single x \u2026 y \u2026 z"},{"location":"msg_format/#array-xyz","text":"The node will send a message with all payload inside an array. The message will contain a payload that is an array of single message. Ex msg.payload[0].payload is the payload of the first device. Each element will contain only the properties payload, meta, meta_changed. The properties topic , payload_format , payload_raw will be on the msg directly.","title":"Array [x,y,z]"},{"location":"msg_format/#maths-formats","text":"Where is specials format that do simple maths on values. The result will be inside the payload with the same structure as the initial payload. Only numeric values are kept, the values like \"1234\" are string and not numeric. The meta property will be always an array with all devices. If some devices don\u2019t have all properties the missing one will be skipped for devices that don\u2019t have it. For examples below the data are: Device x { \"lastupdated\": \"2021-09-06T15:39:13.168\", \"temperature\": 2500 } Device y { \"lastupdated\": \"2021-09-06T15:39:13.168\", \"temperature\": 3000 } Device z { \"lastupdated\": \"2021-09-06T15:39:13.168\", \" humidity\": 5570 }","title":"Maths formats"},{"location":"msg_format/#sum-xyz","text":"All properties of the devices will be added individually. Example results { \"temperature\": 5500, \"humidity\": 5570 } I know adding temperature don\u2019t make sense but could be useful for power usage.","title":"Sum (x+y+z)"},{"location":"msg_format/#average-xyz3","text":"All properties of the devices will be added recursively and then divided by the amount of device that have that property. Example results { \"temperature\": 2750, \"humidity\": 5570 }","title":"Average (x+y+z)/3"},{"location":"msg_format/#min-xyz-y","text":"The result will be a set of minimal value of each property. Example results { \"temperature\": 2500, \"humidity\": 5570 }","title":"Min X+y+Z = y"},{"location":"msg_format/#max-x-y-z-x","text":"The result will be a set of maximal value of each property. Example results { \"temperature\": 3000, \"humidity\": 5570 }","title":"Max X + y + z = X"}]} \ No newline at end of file diff --git a/search/worker.js b/search/worker.js new file mode 100644 index 0000000..8628dbc --- /dev/null +++ b/search/worker.js @@ -0,0 +1,133 @@ +var base_path = 'function' === typeof importScripts ? '.' : '/search/'; +var allowSearch = false; +var index; +var documents = {}; +var lang = ['en']; +var data; + +function getScript(script, callback) { + console.log('Loading script: ' + script); + $.getScript(base_path + script).done(function () { + callback(); + }).fail(function (jqxhr, settings, exception) { + console.log('Error: ' + exception); + }); +} + +function getScriptsInOrder(scripts, callback) { + if (scripts.length === 0) { + callback(); + return; + } + getScript(scripts[0], function() { + getScriptsInOrder(scripts.slice(1), callback); + }); +} + +function loadScripts(urls, callback) { + if( 'function' === typeof importScripts ) { + importScripts.apply(null, urls); + callback(); + } else { + getScriptsInOrder(urls, callback); + } +} + +function onJSONLoaded () { + data = JSON.parse(this.responseText); + var scriptsToLoad = ['lunr.js']; + if (data.config && data.config.lang && data.config.lang.length) { + lang = data.config.lang; + } + if (lang.length > 1 || lang[0] !== "en") { + scriptsToLoad.push('lunr.stemmer.support.js'); + if (lang.length > 1) { + scriptsToLoad.push('lunr.multi.js'); + } + if (lang.includes("ja") || lang.includes("jp")) { + scriptsToLoad.push('tinyseg.js'); + } + for (var i=0; i < lang.length; i++) { + if (lang[i] != 'en') { + scriptsToLoad.push(['lunr', lang[i], 'js'].join('.')); + } + } + } + loadScripts(scriptsToLoad, onScriptsLoaded); +} + +function onScriptsLoaded () { + console.log('All search scripts loaded, building Lunr index...'); + if (data.config && data.config.separator && data.config.separator.length) { + lunr.tokenizer.separator = new RegExp(data.config.separator); + } + + if (data.index) { + index = lunr.Index.load(data.index); + data.docs.forEach(function (doc) { + documents[doc.location] = doc; + }); + console.log('Lunr pre-built index loaded, search ready'); + } else { + index = lunr(function () { + if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) { + this.use(lunr[lang[0]]); + } else if (lang.length > 1) { + this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility + } + this.field('title'); + this.field('text'); + this.ref('location'); + + for (var i=0; i < data.docs.length; i++) { + var doc = data.docs[i]; + this.add(doc); + documents[doc.location] = doc; + } + }); + console.log('Lunr index built, search ready'); + } + allowSearch = true; + postMessage({config: data.config}); + postMessage({allowSearch: allowSearch}); +} + +function init () { + var oReq = new XMLHttpRequest(); + oReq.addEventListener("load", onJSONLoaded); + var index_path = base_path + '/search_index.json'; + if( 'function' === typeof importScripts ){ + index_path = 'search_index.json'; + } + oReq.open("GET", index_path); + oReq.send(); +} + +function search (query) { + if (!allowSearch) { + console.error('Assets for search still loading'); + return; + } + + var resultDocuments = []; + var results = index.search(query); + for (var i=0; i < results.length; i++){ + var result = results[i]; + doc = documents[result.ref]; + doc.summary = doc.text.substring(0, 200); + resultDocuments.push(doc); + } + return resultDocuments; +} + +if( 'function' === typeof importScripts ) { + onmessage = function (e) { + if (e.data.init) { + init(); + } else if (e.data.query) { + postMessage({ results: search(e.data.query) }); + } else { + console.error("Worker - Unrecognized message: " + e); + } + }; +} diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0f8724e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + +