bt-sensors-plugin-sk 1.2.0-beta.0.1.2.a → 1.2.0-beta.0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +7 -0
- package/BTSensor.js +2 -1
- package/README.md +10 -0
- package/classLoader.js +1 -1
- package/package.json +1 -1
- package/public/159.js +1 -1
- package/public/239.js +5 -11
- package/public/540.js +1 -1
- package/public/778.js +1 -1
- package/public/main.js +1 -1
- package/public/remoteEntry.js +1 -1
- package/sensor_classes/BTHome/AbstractBTHomeSensor.js +112 -21
- package/sensor_classes/ShellySBHT003C.js +6 -65
- package/sensor_classes/ShellySBMO003Z.js +58 -0
- package/testqueue.js +64 -0
- package/bt-sensors-plugin-sk.json.bak +0 -121
package/public/540.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see 540.js.LICENSE.txt */
|
|
2
|
-
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[540],{
|
|
2
|
+
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[540],{5287:(e,r,t)=>{var n=t(5228),o="function"==typeof Symbol&&Symbol.for,u=o?Symbol.for("react.element"):60103,f=o?Symbol.for("react.portal"):60106,l=o?Symbol.for("react.fragment"):60107,c=o?Symbol.for("react.strict_mode"):60108,i=o?Symbol.for("react.profiler"):60114,a=o?Symbol.for("react.provider"):60109,s=o?Symbol.for("react.context"):60110,p=o?Symbol.for("react.forward_ref"):60112,y=o?Symbol.for("react.suspense"):60113,d=o?Symbol.for("react.memo"):60115,h=o?Symbol.for("react.lazy"):60116,v="function"==typeof Symbol&&Symbol.iterator;function m(e){for(var r="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t<arguments.length;t++)r+="&args[]="+encodeURIComponent(arguments[t]);return"Minified React error #"+e+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var b={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_={};function S(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||b}function k(){}function g(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||b}S.prototype.isReactComponent={},S.prototype.setState=function(e,r){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(m(85));this.updater.enqueueSetState(this,e,r,"setState")},S.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},k.prototype=S.prototype;var w=g.prototype=new k;w.constructor=g,n(w,S.prototype),w.isPureReactComponent=!0;var $={current:null},C=Object.prototype.hasOwnProperty,E={key:!0,ref:!0,__self:!0,__source:!0};function R(e,r,t){var n,o={},f=null,l=null;if(null!=r)for(n in void 0!==r.ref&&(l=r.ref),void 0!==r.key&&(f=""+r.key),r)C.call(r,n)&&!E.hasOwnProperty(n)&&(o[n]=r[n]);var c=arguments.length-2;if(1===c)o.children=t;else if(1<c){for(var i=Array(c),a=0;a<c;a++)i[a]=arguments[a+2];o.children=i}if(e&&e.defaultProps)for(n in c=e.defaultProps)void 0===o[n]&&(o[n]=c[n]);return{$$typeof:u,type:e,key:f,ref:l,props:o,_owner:$.current}}function x(e){return"object"==typeof e&&null!==e&&e.$$typeof===u}var P=/\/+/g,j=[];function O(e,r,t,n){if(j.length){var o=j.pop();return o.result=e,o.keyPrefix=r,o.func=t,o.context=n,o.count=0,o}return{result:e,keyPrefix:r,func:t,context:n,count:0}}function A(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>j.length&&j.push(e)}function I(e,r,t,n){var o=typeof e;"undefined"!==o&&"boolean"!==o||(e=null);var l=!1;if(null===e)l=!0;else switch(o){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case u:case f:l=!0}}if(l)return t(n,e,""===r?"."+q(e,0):r),1;if(l=0,r=""===r?".":r+":",Array.isArray(e))for(var c=0;c<e.length;c++){var i=r+q(o=e[c],c);l+=I(o,i,t,n)}else if("function"==typeof(i=null===e||"object"!=typeof e?null:"function"==typeof(i=v&&e[v]||e["@@iterator"])?i:null))for(e=i.call(e),c=0;!(o=e.next()).done;)l+=I(o=o.value,i=r+q(o,c++),t,n);else if("object"===o)throw t=""+e,Error(m(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t,""));return l}function U(e,r,t){return null==e?0:I(e,"",r,t)}function q(e,r){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var r={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,(function(e){return r[e]}))}(e.key):r.toString(36)}function F(e,r){e.func.call(e.context,r,e.count++)}function L(e,r,t){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,r,e.count++),Array.isArray(e)?M(e,n,t,(function(e){return e})):null!=e&&(x(e)&&(e=function(e,r){return{$$typeof:u,type:e.type,key:r,ref:e.ref,props:e.props,_owner:e._owner}}(e,o+(!e.key||r&&r.key===e.key?"":(""+e.key).replace(P,"$&/")+"/")+t)),n.push(e))}function M(e,r,t,n,o){var u="";null!=t&&(u=(""+t).replace(P,"$&/")+"/"),U(e,L,r=O(r,u,n,o)),A(r)}var D={current:null};function V(){var e=D.current;if(null===e)throw Error(m(321));return e}var B={ReactCurrentDispatcher:D,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:$,IsSomeRendererActing:{current:!1},assign:n};r.Children={map:function(e,r,t){if(null==e)return e;var n=[];return M(e,n,null,r,t),n},forEach:function(e,r,t){if(null==e)return e;U(e,F,r=O(null,null,r,t)),A(r)},count:function(e){return U(e,(function(){return null}),null)},toArray:function(e){var r=[];return M(e,r,null,(function(e){return e})),r},only:function(e){if(!x(e))throw Error(m(143));return e}},r.Component=S,r.Fragment=l,r.Profiler=i,r.PureComponent=g,r.StrictMode=c,r.Suspense=y,r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=B,r.cloneElement=function(e,r,t){if(null==e)throw Error(m(267,e));var o=n({},e.props),f=e.key,l=e.ref,c=e._owner;if(null!=r){if(void 0!==r.ref&&(l=r.ref,c=$.current),void 0!==r.key&&(f=""+r.key),e.type&&e.type.defaultProps)var i=e.type.defaultProps;for(a in r)C.call(r,a)&&!E.hasOwnProperty(a)&&(o[a]=void 0===r[a]&&void 0!==i?i[a]:r[a])}var a=arguments.length-2;if(1===a)o.children=t;else if(1<a){i=Array(a);for(var s=0;s<a;s++)i[s]=arguments[s+2];o.children=i}return{$$typeof:u,type:e.type,key:f,ref:l,props:o,_owner:c}},r.createContext=function(e,r){return void 0===r&&(r=null),(e={$$typeof:s,_calculateChangedBits:r,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},r.createElement=R,r.createFactory=function(e){var r=R.bind(null,e);return r.type=e,r},r.createRef=function(){return{current:null}},r.forwardRef=function(e){return{$$typeof:p,render:e}},r.isValidElement=x,r.lazy=function(e){return{$$typeof:h,_ctor:e,_status:-1,_result:null}},r.memo=function(e,r){return{$$typeof:d,type:e,compare:void 0===r?null:r}},r.useCallback=function(e,r){return V().useCallback(e,r)},r.useContext=function(e,r){return V().useContext(e,r)},r.useDebugValue=function(){},r.useEffect=function(e,r){return V().useEffect(e,r)},r.useImperativeHandle=function(e,r,t){return V().useImperativeHandle(e,r,t)},r.useLayoutEffect=function(e,r){return V().useLayoutEffect(e,r)},r.useMemo=function(e,r){return V().useMemo(e,r)},r.useReducer=function(e,r,t){return V().useReducer(e,r,t)},r.useRef=function(e){return V().useRef(e)},r.useState=function(e){return V().useState(e)},r.version="16.14.0"},6540:(e,r,t)=>{e.exports=t(5287)}}]);
|
package/public/778.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see 778.js.LICENSE.txt */
|
|
2
|
-
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[540,778],{
|
|
2
|
+
"use strict";(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[540,778],{5228:e=>{var r=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var r={},t=0;t<10;t++)r["_"+String.fromCharCode(t)]=t;if("0123456789"!==Object.getOwnPropertyNames(r).map((function(e){return r[e]})).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach((function(e){n[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(e){return!1}}()?Object.assign:function(e,o){for(var u,c,f=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),l=1;l<arguments.length;l++){for(var i in u=Object(arguments[l]))t.call(u,i)&&(f[i]=u[i]);if(r){c=r(u);for(var a=0;a<c.length;a++)n.call(u,c[a])&&(f[c[a]]=u[c[a]])}}return f}},5287:(e,r,t)=>{var n=t(5228),o="function"==typeof Symbol&&Symbol.for,u=o?Symbol.for("react.element"):60103,c=o?Symbol.for("react.portal"):60106,f=o?Symbol.for("react.fragment"):60107,l=o?Symbol.for("react.strict_mode"):60108,i=o?Symbol.for("react.profiler"):60114,a=o?Symbol.for("react.provider"):60109,s=o?Symbol.for("react.context"):60110,p=o?Symbol.for("react.forward_ref"):60112,y=o?Symbol.for("react.suspense"):60113,d=o?Symbol.for("react.memo"):60115,h=o?Symbol.for("react.lazy"):60116,b="function"==typeof Symbol&&Symbol.iterator;function v(e){for(var r="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t<arguments.length;t++)r+="&args[]="+encodeURIComponent(arguments[t]);return"Minified React error #"+e+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_={};function g(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||m}function S(){}function k(e,r,t){this.props=e,this.context=r,this.refs=_,this.updater=t||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,r){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(v(85));this.updater.enqueueSetState(this,e,r,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},S.prototype=g.prototype;var w=k.prototype=new S;w.constructor=k,n(w,g.prototype),w.isPureReactComponent=!0;var j={current:null},O=Object.prototype.hasOwnProperty,C={key:!0,ref:!0,__self:!0,__source:!0};function $(e,r,t){var n,o={},c=null,f=null;if(null!=r)for(n in void 0!==r.ref&&(f=r.ref),void 0!==r.key&&(c=""+r.key),r)O.call(r,n)&&!C.hasOwnProperty(n)&&(o[n]=r[n]);var l=arguments.length-2;if(1===l)o.children=t;else if(1<l){for(var i=Array(l),a=0;a<l;a++)i[a]=arguments[a+2];o.children=i}if(e&&e.defaultProps)for(n in l=e.defaultProps)void 0===o[n]&&(o[n]=l[n]);return{$$typeof:u,type:e,key:c,ref:f,props:o,_owner:j.current}}function E(e){return"object"==typeof e&&null!==e&&e.$$typeof===u}var P=/\/+/g,x=[];function R(e,r,t,n){if(x.length){var o=x.pop();return o.result=e,o.keyPrefix=r,o.func=t,o.context=n,o.count=0,o}return{result:e,keyPrefix:r,func:t,context:n,count:0}}function A(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>x.length&&x.push(e)}function I(e,r,t,n){var o=typeof e;"undefined"!==o&&"boolean"!==o||(e=null);var f=!1;if(null===e)f=!0;else switch(o){case"string":case"number":f=!0;break;case"object":switch(e.$$typeof){case u:case c:f=!0}}if(f)return t(n,e,""===r?"."+U(e,0):r),1;if(f=0,r=""===r?".":r+":",Array.isArray(e))for(var l=0;l<e.length;l++){var i=r+U(o=e[l],l);f+=I(o,i,t,n)}else if("function"==typeof(i=null===e||"object"!=typeof e?null:"function"==typeof(i=b&&e[b]||e["@@iterator"])?i:null))for(e=i.call(e),l=0;!(o=e.next()).done;)f+=I(o=o.value,i=r+U(o,l++),t,n);else if("object"===o)throw t=""+e,Error(v(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t,""));return f}function q(e,r,t){return null==e?0:I(e,"",r,t)}function U(e,r){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var r={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,(function(e){return r[e]}))}(e.key):r.toString(36)}function F(e,r){e.func.call(e.context,r,e.count++)}function L(e,r,t){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,r,e.count++),Array.isArray(e)?M(e,n,t,(function(e){return e})):null!=e&&(E(e)&&(e=function(e,r){return{$$typeof:u,type:e.type,key:r,ref:e.ref,props:e.props,_owner:e._owner}}(e,o+(!e.key||r&&r.key===e.key?"":(""+e.key).replace(P,"$&/")+"/")+t)),n.push(e))}function M(e,r,t,n,o){var u="";null!=t&&(u=(""+t).replace(P,"$&/")+"/"),q(e,L,r=R(r,u,n,o)),A(r)}var N={current:null};function D(){var e=N.current;if(null===e)throw Error(v(321));return e}var T={ReactCurrentDispatcher:N,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:j,IsSomeRendererActing:{current:!1},assign:n};r.Children={map:function(e,r,t){if(null==e)return e;var n=[];return M(e,n,null,r,t),n},forEach:function(e,r,t){if(null==e)return e;q(e,F,r=R(null,null,r,t)),A(r)},count:function(e){return q(e,(function(){return null}),null)},toArray:function(e){var r=[];return M(e,r,null,(function(e){return e})),r},only:function(e){if(!E(e))throw Error(v(143));return e}},r.Component=g,r.Fragment=f,r.Profiler=i,r.PureComponent=k,r.StrictMode=l,r.Suspense=y,r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=T,r.cloneElement=function(e,r,t){if(null==e)throw Error(v(267,e));var o=n({},e.props),c=e.key,f=e.ref,l=e._owner;if(null!=r){if(void 0!==r.ref&&(f=r.ref,l=j.current),void 0!==r.key&&(c=""+r.key),e.type&&e.type.defaultProps)var i=e.type.defaultProps;for(a in r)O.call(r,a)&&!C.hasOwnProperty(a)&&(o[a]=void 0===r[a]&&void 0!==i?i[a]:r[a])}var a=arguments.length-2;if(1===a)o.children=t;else if(1<a){i=Array(a);for(var s=0;s<a;s++)i[s]=arguments[s+2];o.children=i}return{$$typeof:u,type:e.type,key:c,ref:f,props:o,_owner:l}},r.createContext=function(e,r){return void 0===r&&(r=null),(e={$$typeof:s,_calculateChangedBits:r,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},r.createElement=$,r.createFactory=function(e){var r=$.bind(null,e);return r.type=e,r},r.createRef=function(){return{current:null}},r.forwardRef=function(e){return{$$typeof:p,render:e}},r.isValidElement=E,r.lazy=function(e){return{$$typeof:h,_ctor:e,_status:-1,_result:null}},r.memo=function(e,r){return{$$typeof:d,type:e,compare:void 0===r?null:r}},r.useCallback=function(e,r){return D().useCallback(e,r)},r.useContext=function(e,r){return D().useContext(e,r)},r.useDebugValue=function(){},r.useEffect=function(e,r){return D().useEffect(e,r)},r.useImperativeHandle=function(e,r,t){return D().useImperativeHandle(e,r,t)},r.useLayoutEffect=function(e,r){return D().useLayoutEffect(e,r)},r.useMemo=function(e,r){return D().useMemo(e,r)},r.useReducer=function(e,r,t){return D().useReducer(e,r,t)},r.useRef=function(e){return D().useRef(e)},r.useState=function(e){return D().useState(e)},r.version="16.14.0"},6540:(e,r,t)=>{e.exports=t(5287)}}]);
|
package/public/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var e,r,t={
|
|
1
|
+
(()=>{var e,r,t={9445:()=>{}},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={exports:{}};return t[e](a,a.exports,o),a.exports}o.m=t,o.c=n,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>e+".js",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",o.l=(t,n,a,i)=>{if(e[t])e[t].push(n);else{var s,l;if(void 0!==a)for(var u=document.getElementsByTagName("script"),c=0;c<u.length;c++){var p=u[c];if(p.getAttribute("src")==t||p.getAttribute("data-webpack")==r+a){s=p;break}}s||(l=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.setAttribute("data-webpack",r+a),s.src=t),e[t]=[n];var d=(r,n)=>{s.onerror=s.onload=null,clearTimeout(f);var o=e[t];if(delete e[t],s.parentNode&&s.parentNode.removeChild(s),o&&o.forEach((e=>e(n))),r)return r(n)},f=setTimeout(d.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=d.bind(null,s.onerror),s.onload=d.bind(null,s.onload),l&&document.head.appendChild(s)}},(()=>{o.S={};var e={},r={};o.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];o.o(o.S,t)||(o.S[t]={});var i=o.S[t],s="bt-sensors-plugin-sk",l=[];return"default"===t&&((e,r,t,n)=>{var a=i[e]=i[e]||{},l=a[r];(!l||!l.loaded&&(1!=!l.eager?n:s>l.from))&&(a[r]={get:()=>o.e(778).then((()=>()=>o(6540))),from:s,eager:!1})})("react","16.14.0"),e[t]=l.length?Promise.all(l).then((()=>e[t]=1)):1}}})(),(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var r=o.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={792:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),s=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;s.message="Loading chunk "+r+" failed.\n("+a+": "+i+")",s.name="ChunkLoadError",s.type=a,s.request=i,n[1](s)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[i,s,l]=t,u=0;if(i.some((r=>0!==e[r]))){for(n in s)o.o(s,n)&&(o.m[n]=s[n]);l&&l(o)}for(r&&r(t);u<i.length;u++)a=i[u],o.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o(9445)})();
|
package/public/remoteEntry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var bt_sensors_plugin_sk;(()=>{"use strict";var e,r,t,n,a,o,i,u,s,l,f,d,c,p,h,v,g,b,m,y,w,k={
|
|
1
|
+
var bt_sensors_plugin_sk;(()=>{"use strict";var e,r,t,n,a,o,i,u,s,l,f,d,c,p,h,v,g,b,m,y,w,k={3237:(e,r,t)=>{var n={"./PluginConfigurationPanel":()=>Promise.all([t.e(239),t.e(159)]).then((()=>()=>t(2995)))},a=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),o=(e,r)=>{if(t.S){var n="default",a=t.S[n];if(a&&a!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>a,init:()=>o})}},S={};function _(e){var r=S[e];if(void 0!==r)return r.exports;var t=S[e]={id:e,loaded:!1,exports:{}};return k[e](t,t.exports,_),t.loaded=!0,t.exports}_.m=k,_.c=S,_.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return _.d(r,{a:r}),r},_.d=(e,r)=>{for(var t in r)_.o(r,t)&&!_.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},_.f={},_.e=e=>Promise.all(Object.keys(_.f).reduce(((r,t)=>(_.f[t](e,r),r)),[])),_.u=e=>e+".js",_.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),_.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",_.l=(t,n,a,o)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==a)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var f=s[l];if(f.getAttribute("src")==t||f.getAttribute("data-webpack")==r+a){i=f;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,_.nc&&i.setAttribute("nonce",_.nc),i.setAttribute("data-webpack",r+a),i.src=t),e[t]=[n];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var a=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach((e=>e(n))),r)return r(n)},c=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),u&&document.head.appendChild(i)}},_.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},_.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{_.S={};var e={},r={};_.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];_.o(_.S,t)||(_.S[t]={});var o=_.S[t],i="bt-sensors-plugin-sk",u=[];return"default"===t&&((e,r,t,n)=>{var a=o[e]=o[e]||{},u=a[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(a[r]={get:()=>_.e(778).then((()=>()=>_(6540))),from:i,eager:!1})})("react","16.14.0"),e[t]=u.length?Promise.all(u).then((()=>e[t]=1)):1}}})(),(()=>{var e;_.g.importScripts&&(e=_.g.location+"");var r=_.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),_.p=e})(),t=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var a=e[n],o=(typeof a)[0];if(n>=r.length)return"u"==o;var i=r[n],u=(typeof i)[0];if(o!=u)return"o"==o&&"n"==u||"s"==u||"u"==o;if("o"!=o&&"u"!=o&&a!=i)return a<i;n++}},a=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,o=1;o<e.length;o++)n--,t+="u"==(typeof(u=e[o]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(o=1;o<e.length;o++){var u=e[o];i.push(0===u?"not("+s()+")":1===u?"("+s()+" || "+s()+")":2===u?i.pop()+" "+i.pop():a(u))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},o=(e,r)=>{if(0 in e){r=t(r);var n=e[0],a=n<0;a&&(n=-n-1);for(var i=0,u=1,s=!0;;u++,i++){var l,f,d=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(f=(typeof(l=r[i]))[0]))return!s||("u"==d?u>n&&!a:""==d!=a);if("u"==f){if(!s||"u"!=d)return!1}else if(s)if(d==f)if(u<=n){if(l!=e[u])return!1}else{if(a?l>e[u]:l<e[u])return!1;l!=e[u]&&(s=!1)}else if("s"!=d&&"n"!=d){if(a||u<=n)return!1;s=!1,u--}else{if(u<=n||f<d!=a)return!1;s=!1}else"s"!=d&&"n"!=d&&(s=!1,u--)}}var c=[],p=c.pop.bind(c);for(i=1;i<e.length;i++){var h=e[i];c.push(1==h?p()|p():2==h?p()&p():h?o(h,r):!p())}return!!p()},i=(e,r)=>e&&_.o(e,r),u=e=>(e.loaded=1,e.get()),s=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),l=(e,r,t)=>{var a=t?s(e[r]):e[r];return(r=Object.keys(a).reduce(((e,r)=>!e||n(e,r)?r:e),0))&&a[r]},f=(e,r,t,a)=>{var i=a?s(e[r]):e[r];return(r=Object.keys(i).reduce(((e,r)=>!o(t,r)||e&&!n(e,r)?e:r),0))&&i[r]},d=(e,r,t,n,o)=>{var i=e[t];return"No satisfying version ("+a(n)+")"+(o?" for eager consumption":"")+" of shared module "+t+" found in shared scope "+r+".\nAvailable versions: "+Object.keys(i).map((e=>e+" from "+i[e].from)).join(", ")},c=e=>{throw new Error(e)},h=(e,r,t)=>t?t():((e,r)=>c("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(p=e=>function(r,t,n,a,o){var i=_.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,_.S[r],t,!1,a,o)):e(r,_.S[r],t,n,a,o)})(((e,r,t,n,a)=>i(r,t)?u(l(r,t,n)):h(e,t,a))),g=p(((e,r,t,n,a,o)=>{if(!i(r,t))return h(e,t,o);var s=f(r,t,a,n);return s?u(s):o?o():void c(d(r,e,t,a,n))})),b={},m={1490:()=>g("default","react",!1,[,[1,17,0,0],[1,16,8,0],1],(()=>_.e(540).then((()=>()=>_(6540))))),2085:()=>g("default","react",!1,[1,16,14,0],(()=>_.e(540).then((()=>()=>_(6540))))),2417:()=>g("default","react",!1,[0,16,8,0],(()=>_.e(540).then((()=>()=>_(6540))))),4115:()=>g("default","react",!1,[,[1,19,0,0,,"rc",1],[1,18,0,0],[1,17,0,0,,"rc",1],[1,16,8,0],1,1,1],(()=>_.e(540).then((()=>()=>_(6540))))),4147:()=>g("default","react",!1,[1,16,13,1],(()=>_.e(540).then((()=>()=>_(6540))))),4167:()=>v("default","react",!1,(()=>_.e(540).then((()=>()=>_(6540))))),4564:()=>g("default","react",!1,[0,16,14,0],(()=>_.e(540).then((()=>()=>_(6540))))),6932:()=>g("default","react",!1,[0,15,0,0],(()=>_.e(540).then((()=>()=>_(6540))))),7227:()=>g("default","react",!1,[0,16,6,0],(()=>_.e(540).then((()=>()=>_(6540))))),7920:()=>g("default","react",!1,[,[0,17],[1,16,14,0],1],(()=>_.e(540).then((()=>()=>_(6540))))),8271:()=>g("default","react",!1,[0,0,14,0],(()=>_.e(540).then((()=>()=>_(6540)))))},y={159:[1490,2085,2417,4115,4147,4167,4564,6932,7227,7920,8271]},w={},_.f.consumes=(e,r)=>{_.o(y,e)&&y[e].forEach((e=>{if(_.o(b,e))return r.push(b[e]);if(!w[e]){var t=r=>{b[e]=0,_.m[e]=t=>{delete _.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete b[e],_.m[e]=t=>{throw delete _.c[e],r}};try{var a=m[e]();a.then?r.push(b[e]=a.then(t).catch(n)):t(a)}catch(e){n(e)}}}))},(()=>{var e={592:0};_.f.j=(r,t)=>{var n=_.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,a)=>n=e[r]=[t,a]));t.push(n[2]=a);var o=_.p+_.u(r),i=new Error;_.l(o,(t=>{if(_.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+a+": "+o+")",i.name="ChunkLoadError",i.type=a,i.request=o,n[1](i)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[o,i,u]=t,s=0;if(o.some((r=>0!==e[r]))){for(n in i)_.o(i,n)&&(_.m[n]=i[n]);u&&u(_)}for(r&&r(t);s<o.length;s++)a=o[s],_.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var j=_(3237);bt_sensors_plugin_sk=j})();
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
const BTSensor = require("../../BTSensor");
|
|
2
2
|
const BTHomeServiceData = require("./BTHomeServiceData");
|
|
3
3
|
const KaitaiStream = require("kaitai-struct/KaitaiStream");
|
|
4
|
+
/**
|
|
5
|
+
* @typedef ButtonPressEvent {string}
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Shelly Blu devices support single press and hold press options.
|
|
9
|
+
* @type {Readonly<{PRESS: string, HOLD_PRESS: string}>}
|
|
10
|
+
*/
|
|
4
11
|
|
|
12
|
+
const ButtonPressEvent = Object.freeze({
|
|
13
|
+
PRESS: "press",
|
|
14
|
+
HOLD_PRESS: "hold_press",
|
|
15
|
+
});
|
|
5
16
|
/**
|
|
6
17
|
* Base class for sensors publishing BTHome data.
|
|
7
18
|
*
|
|
@@ -11,6 +22,8 @@ const KaitaiStream = require("kaitai-struct/KaitaiStream");
|
|
|
11
22
|
* @see https://bthome.io/
|
|
12
23
|
*/
|
|
13
24
|
class AbstractBTHomeSensor extends BTSensor {
|
|
25
|
+
|
|
26
|
+
|
|
14
27
|
/**
|
|
15
28
|
* Offset from Celsius to Kelvin, used to convert between these units.
|
|
16
29
|
* 273.15 degrees Kelvin correspond to 0 degrees Celsius.
|
|
@@ -25,16 +38,25 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
25
38
|
*/
|
|
26
39
|
static BTHOME_SERVICE_ID = "0000fcd2-0000-1000-8000-00805f9b34fb";
|
|
27
40
|
|
|
41
|
+
|
|
42
|
+
|
|
28
43
|
/**
|
|
29
|
-
* Returns
|
|
44
|
+
* Returns the `AbstractBTHomeSensor` sensor class if the specified device has been identified as Shelly BLU H&T.
|
|
30
45
|
*
|
|
31
|
-
* @param
|
|
32
|
-
* @
|
|
33
|
-
* @return {any|null} Returns the measurement data for the given object ID, or `null`, if the BTHomeData does not
|
|
34
|
-
* contain the measurement.
|
|
46
|
+
* @param device The Bluetooth device to be identified.
|
|
47
|
+
* @returns {Promise<AbstractBTHomeSensor|null>} Returns the sensor class if the device has been identified, or null.
|
|
35
48
|
*/
|
|
36
|
-
static
|
|
37
|
-
|
|
49
|
+
static async identify(device) {
|
|
50
|
+
if (
|
|
51
|
+
(await this.hasBtHomeServiceData(device)) &&
|
|
52
|
+
(await this.hasName(
|
|
53
|
+
device,
|
|
54
|
+
this.SHORTENED_LOCAL_NAME,
|
|
55
|
+
))
|
|
56
|
+
) {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
38
60
|
}
|
|
39
61
|
|
|
40
62
|
/**
|
|
@@ -56,12 +78,12 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
56
78
|
* if not.
|
|
57
79
|
*/
|
|
58
80
|
static async hasBtHomeServiceData(device) {
|
|
59
|
-
const serviceData = await
|
|
81
|
+
const serviceData = await this.getDeviceProp(
|
|
60
82
|
device,
|
|
61
83
|
"ServiceData",
|
|
62
84
|
);
|
|
63
85
|
if (serviceData) {
|
|
64
|
-
if (
|
|
86
|
+
if (this.BTHOME_SERVICE_ID in serviceData) {
|
|
65
87
|
return true;
|
|
66
88
|
}
|
|
67
89
|
}
|
|
@@ -88,7 +110,7 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
88
110
|
* if not.
|
|
89
111
|
*/
|
|
90
112
|
static async hasName(device, name) {
|
|
91
|
-
const deviceName = await
|
|
113
|
+
const deviceName = await this.getDeviceProp(device, "Name");
|
|
92
114
|
if (deviceName) {
|
|
93
115
|
if (deviceName === name) {
|
|
94
116
|
return true;
|
|
@@ -96,15 +118,25 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
96
118
|
}
|
|
97
119
|
return false;
|
|
98
120
|
}
|
|
99
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Returns measurement data for the given object ID from the given BTHomeData.
|
|
123
|
+
*
|
|
124
|
+
* @param btHomeData {BTHomeServiceData.BthomeServiceData}
|
|
125
|
+
* @param objectId {number}
|
|
126
|
+
* @return {any|null} Returns the measurement data for the given object ID, or `null`, if the BTHomeData does not
|
|
127
|
+
* contain the measurement.
|
|
128
|
+
*/
|
|
129
|
+
getSensorDataByObjectId(btHomeData, objectId) {
|
|
130
|
+
return btHomeData.measurement.find((m) => m.objectId === objectId)?.data;
|
|
131
|
+
}
|
|
100
132
|
/**
|
|
101
133
|
* Extracts battery level from the given BTHome data.
|
|
102
134
|
*
|
|
103
135
|
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
104
136
|
* @returns {number|null} The device's battery level as ratio (0‒1).
|
|
105
137
|
*/
|
|
106
|
-
|
|
107
|
-
const batteryLevel =
|
|
138
|
+
parseBatteryLevel(btHomeData) {
|
|
139
|
+
const batteryLevel = this.getSensorDataByObjectId(
|
|
108
140
|
btHomeData,
|
|
109
141
|
BTHomeServiceData.BthomeObjectId.SENSOR_BATTERY,
|
|
110
142
|
)?.battery;
|
|
@@ -120,14 +152,14 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
120
152
|
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
121
153
|
* @returns {number|null} The temperature in Kelvin.
|
|
122
154
|
*/
|
|
123
|
-
|
|
124
|
-
const tempCelsius =
|
|
155
|
+
parseTemperature(btHomeData) {
|
|
156
|
+
const tempCelsius = this.getSensorDataByObjectId(
|
|
125
157
|
btHomeData,
|
|
126
158
|
BTHomeServiceData.BthomeObjectId.SENSOR_TEMPERATURE_0_1,
|
|
127
159
|
)?.temperature;
|
|
128
160
|
if (tempCelsius) {
|
|
129
161
|
return Number.parseFloat(
|
|
130
|
-
(
|
|
162
|
+
(this.KELVIN_OFFSET + tempCelsius).toFixed(2),
|
|
131
163
|
);
|
|
132
164
|
}
|
|
133
165
|
return null;
|
|
@@ -139,8 +171,8 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
139
171
|
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
140
172
|
* @returns {number|null} The relative humidity as ratio (0‒1).
|
|
141
173
|
*/
|
|
142
|
-
|
|
143
|
-
const humidity =
|
|
174
|
+
parseHumidity(btHomeData) {
|
|
175
|
+
const humidity = this.getSensorDataByObjectId(
|
|
144
176
|
btHomeData,
|
|
145
177
|
BTHomeServiceData.BthomeObjectId.SENSOR_HUMIDITY,
|
|
146
178
|
)?.humidity;
|
|
@@ -150,14 +182,42 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
150
182
|
return null;
|
|
151
183
|
}
|
|
152
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Extracts luminance from the given BTHome data.
|
|
187
|
+
*
|
|
188
|
+
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
189
|
+
* @returns {number|null} The luminance as float.
|
|
190
|
+
*/
|
|
191
|
+
parseIlluminance(btHomeData) {
|
|
192
|
+
const illuminance = this.getSensorDataByObjectId(
|
|
193
|
+
btHomeData,
|
|
194
|
+
BTHomeServiceData.BthomeObjectId.SENSOR_ILLUMINANCE_0_01,
|
|
195
|
+
)?.illuminance;
|
|
196
|
+
return illuminance;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Extracts motion detection from the given BTHome data.
|
|
200
|
+
*
|
|
201
|
+
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
202
|
+
* @returns {Boolean|null} The device's button press state.
|
|
203
|
+
*/
|
|
204
|
+
parseMotion(btHomeData) {
|
|
205
|
+
const motion = this.getSensorDataByObjectId(
|
|
206
|
+
btHomeData,
|
|
207
|
+
BTHomeServiceData.BthomeObjectId.BINARY_MOTION,
|
|
208
|
+
)?.motion;
|
|
209
|
+
return motion.intValue==1
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
153
213
|
/**
|
|
154
214
|
* Extracts button press event from the given BTHome data.
|
|
155
215
|
*
|
|
156
216
|
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
157
217
|
* @returns {BTHomeServiceData.ButtonEventType|null} The device's button press state.
|
|
158
218
|
*/
|
|
159
|
-
|
|
160
|
-
const buttonEvent =
|
|
219
|
+
parseButton(btHomeData) {
|
|
220
|
+
const buttonEvent = this.getSensorDataByObjectId(
|
|
161
221
|
btHomeData,
|
|
162
222
|
BTHomeServiceData.BthomeObjectId.EVENT_BUTTON,
|
|
163
223
|
)?.event;
|
|
@@ -165,8 +225,38 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
165
225
|
return buttonEvent;
|
|
166
226
|
}
|
|
167
227
|
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Parses the relevant button press events for the Shelly BLU H&T from the specified BTHome data. This device only
|
|
232
|
+
* uses a subset of all available BTHome button press events.
|
|
233
|
+
*
|
|
234
|
+
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
235
|
+
* @returns {ButtonPressEvent|null} The device's button state.
|
|
236
|
+
* @see https://shelly-api-docs.shelly.cloud/docs-ble/Devices/ht/#button-press-events
|
|
237
|
+
* @see https://bthome.io/format/
|
|
238
|
+
*/
|
|
239
|
+
parseShellyButton(btHomeData) {
|
|
240
|
+
const buttonEvent = this.parseButton(btHomeData);
|
|
241
|
+
if (buttonEvent) {
|
|
242
|
+
if (buttonEvent === BTHomeServiceData.ButtonEventType.PRESS) {
|
|
243
|
+
return ButtonPressEvent.PRESS;
|
|
244
|
+
/*
|
|
245
|
+
* Prior to firmware version 1.0.20, the hold press event is indicated by 0xFE, which does
|
|
246
|
+
* not conform with the BTHome standard.
|
|
247
|
+
*/
|
|
248
|
+
}
|
|
249
|
+
if (
|
|
250
|
+
buttonEvent === BTHomeServiceData.ButtonEventType.HOLD_PRESS ||
|
|
251
|
+
buttonEvent === 0xfe
|
|
252
|
+
) {
|
|
253
|
+
return ButtonPressEvent.HOLD_PRESS;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
168
257
|
}
|
|
169
258
|
|
|
259
|
+
|
|
170
260
|
propertiesChanged(props) {
|
|
171
261
|
super.propertiesChanged(props);
|
|
172
262
|
|
|
@@ -176,7 +266,7 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
176
266
|
}
|
|
177
267
|
|
|
178
268
|
// Retrieve BTHome data
|
|
179
|
-
const buffer = this.getServiceData(
|
|
269
|
+
const buffer = this.getServiceData(this.constructor.BTHOME_SERVICE_ID);
|
|
180
270
|
if (!buffer) {
|
|
181
271
|
this.debug(
|
|
182
272
|
`ServiceData does not contain BTHome service, which is unexpected for ${this.getDisplayName()}`,
|
|
@@ -189,6 +279,7 @@ class AbstractBTHomeSensor extends BTSensor {
|
|
|
189
279
|
const btHomeData = new BTHomeServiceData(new KaitaiStream(buffer));
|
|
190
280
|
this.emitValuesFrom(btHomeData);
|
|
191
281
|
} catch (e) {
|
|
282
|
+
this.debug(e)
|
|
192
283
|
throw new Error(
|
|
193
284
|
`Unable to parse BTHome data for ${this.getDisplayName()}`,
|
|
194
285
|
);
|
|
@@ -7,7 +7,7 @@ const AbstractBTHomeSensor = require("./BTHome/AbstractBTHomeSensor");
|
|
|
7
7
|
* This sensor is publishing data utilising the BTHome format and inherits from {@link AbstractBTHomeSensor}.
|
|
8
8
|
*/
|
|
9
9
|
class ShellySBHT003C extends AbstractBTHomeSensor {
|
|
10
|
-
static Domain =
|
|
10
|
+
static Domain = this.SensorDomains.environmental
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The shortened local name as advertised by the Shelly BLU H&T.
|
|
@@ -15,66 +15,7 @@ class ShellySBHT003C extends AbstractBTHomeSensor {
|
|
|
15
15
|
*/
|
|
16
16
|
static SHORTENED_LOCAL_NAME = "SBHT-003C";
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
* @typedef ButtonPressEvent {string}
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
|
-
* The Shelly BLU H&T only supports single press and hold press options.
|
|
23
|
-
* @type {Readonly<{PRESS: string, HOLD_PRESS: string}>}
|
|
24
|
-
*/
|
|
25
|
-
static ButtonPressEvent = Object.freeze({
|
|
26
|
-
PRESS: "press",
|
|
27
|
-
HOLD_PRESS: "hold_press",
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Returns the `ShellySBHT003C` sensor class if the specified device has been identified as Shelly BLU H&T.
|
|
32
|
-
*
|
|
33
|
-
* @param device The Bluetooth device to be identified.
|
|
34
|
-
* @returns {Promise<ShellySBHT003C|null>} Returns the sensor class if the device has been identified, or null.
|
|
35
|
-
*/
|
|
36
|
-
static async identify(device) {
|
|
37
|
-
if (
|
|
38
|
-
(await ShellySBHT003C.hasBtHomeServiceData(device)) &&
|
|
39
|
-
(await ShellySBHT003C.hasName(
|
|
40
|
-
device,
|
|
41
|
-
ShellySBHT003C.SHORTENED_LOCAL_NAME,
|
|
42
|
-
))
|
|
43
|
-
) {
|
|
44
|
-
return ShellySBHT003C;
|
|
45
|
-
}
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Parses the relevant button press events for the Shelly BLU H&T from the specified BTHome data. This device only
|
|
51
|
-
* uses a subset of all available BTHome button press events.
|
|
52
|
-
*
|
|
53
|
-
* @param btHomeData {BTHomeServiceData.BthomeServiceData} The BTHome data provided by the device.
|
|
54
|
-
* @returns {ShellySBHT003C.ButtonPressEvent|null} The device's button state.
|
|
55
|
-
* @see https://shelly-api-docs.shelly.cloud/docs-ble/Devices/ht/#button-press-events
|
|
56
|
-
* @see https://bthome.io/format/
|
|
57
|
-
*/
|
|
58
|
-
static parseShellySBHT003CButton(btHomeData) {
|
|
59
|
-
const buttonEvent = ShellySBHT003C.parseButton(btHomeData);
|
|
60
|
-
if (buttonEvent) {
|
|
61
|
-
if (buttonEvent === BTHomeServiceData.ButtonEventType.PRESS) {
|
|
62
|
-
return ShellySBHT003C.ButtonPressEvent.PRESS;
|
|
63
|
-
/*
|
|
64
|
-
* Prior to firmware version 1.0.20, the hold press event is indicated by 0xFE, which does
|
|
65
|
-
* not conform with the BTHome standard.
|
|
66
|
-
*/
|
|
67
|
-
}
|
|
68
|
-
if (
|
|
69
|
-
buttonEvent === BTHomeServiceData.ButtonEventType.HOLD_PRESS ||
|
|
70
|
-
buttonEvent === 0xfe
|
|
71
|
-
) {
|
|
72
|
-
return ShellySBHT003C.ButtonPressEvent.HOLD_PRESS;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
|
|
18
|
+
|
|
78
19
|
initSchema() {
|
|
79
20
|
super.initSchema()
|
|
80
21
|
this.addDefaultParam("zone")
|
|
@@ -82,24 +23,24 @@ class ShellySBHT003C extends AbstractBTHomeSensor {
|
|
|
82
23
|
this.addDefaultPath(
|
|
83
24
|
"battery",
|
|
84
25
|
"sensors.batteryStrength")
|
|
85
|
-
.read=
|
|
26
|
+
.read=this.parseBatteryLevel.bind(this)
|
|
86
27
|
|
|
87
28
|
this.addDefaultPath(
|
|
88
29
|
"temp",
|
|
89
30
|
"environment.temperature"
|
|
90
31
|
)
|
|
91
|
-
.read=
|
|
32
|
+
.read=this.parseTemperature.bind(this)
|
|
92
33
|
|
|
93
34
|
this.addDefaultPath(
|
|
94
35
|
"humidity",
|
|
95
36
|
"environment.humidity")
|
|
96
|
-
.read=
|
|
37
|
+
.read=this.parseHumidity.bind(this),
|
|
97
38
|
|
|
98
39
|
this.addMetadatum(
|
|
99
40
|
"button",
|
|
100
41
|
"enum",
|
|
101
42
|
"button",
|
|
102
|
-
|
|
43
|
+
this.parseShellyButton.bind(this),
|
|
103
44
|
)
|
|
104
45
|
.default="sensors.{macAndName}.button"
|
|
105
46
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const BTHomeServiceData = require("./BTHome/BTHomeServiceData");
|
|
2
|
+
const AbstractBTHomeSensor = require("./BTHome/AbstractBTHomeSensor");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Sensor class representing the Shelly BLU H&T.
|
|
6
|
+
*
|
|
7
|
+
* This sensor is publishing data utilising the BTHome format and inherits from {@link AbstractBTHomeSensor}.
|
|
8
|
+
*/
|
|
9
|
+
class ShellySBMO003Z extends AbstractBTHomeSensor {
|
|
10
|
+
static Domain = this.SensorDomains.environmental
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The shortened local name as advertised by the Shelly BLU H&T.
|
|
14
|
+
* @type {string}
|
|
15
|
+
*/
|
|
16
|
+
static SHORTENED_LOCAL_NAME = "SBMO-003Z";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
initSchema() {
|
|
20
|
+
super.initSchema()
|
|
21
|
+
this.addDefaultParam("zone")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
this.addMetadatum(
|
|
25
|
+
"motion",
|
|
26
|
+
"boolean",
|
|
27
|
+
"motion detected",
|
|
28
|
+
this.parseMotion.bind(this)
|
|
29
|
+
)
|
|
30
|
+
.default="environment.{zone}.motion"
|
|
31
|
+
|
|
32
|
+
this.addMetadatum(
|
|
33
|
+
"illuminance",
|
|
34
|
+
"Lux",
|
|
35
|
+
"illuminance in zone",
|
|
36
|
+
this.parseIlluminance.bind(this)
|
|
37
|
+
)
|
|
38
|
+
.default="environment.{zone}.illuminance"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
this.addDefaultPath(
|
|
42
|
+
"battery",
|
|
43
|
+
"sensors.batteryStrength")
|
|
44
|
+
.read=this.parseBatteryLevel.bind(this)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
this.addMetadatum(
|
|
48
|
+
"button",
|
|
49
|
+
"enum",
|
|
50
|
+
"button",
|
|
51
|
+
this.parseShellyButton.bind(this),
|
|
52
|
+
)
|
|
53
|
+
.default="sensors.{macAndName}.button"
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = ShellySBMO003Z;
|
package/testqueue.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import {createBluetooth} from 'node-ble'
|
|
4
|
+
|
|
5
|
+
import {AutoQueue} from "./Queue.js"
|
|
6
|
+
import {Variant} from 'dbus-next'
|
|
7
|
+
|
|
8
|
+
const {bluetooth, destroy} = createBluetooth()
|
|
9
|
+
const connectQueue = new AutoQueue()
|
|
10
|
+
const adapter = await bluetooth.getAdapter("hci0")
|
|
11
|
+
await adapter.startDiscovery()
|
|
12
|
+
|
|
13
|
+
function deviceConnect(mac) {
|
|
14
|
+
|
|
15
|
+
/* CAUTION: HACK AHEAD
|
|
16
|
+
|
|
17
|
+
Bluez for some cockamamie reason (It's 2025 for chrissake.
|
|
18
|
+
BLUETOOTH ISN'T JUST FOR DESKTOPS ANYMORE, BLUEZ DEVS!)
|
|
19
|
+
SUSPENDS scanning while connected to a device.
|
|
20
|
+
|
|
21
|
+
The next line of code gives the scanner a kick in the arse,
|
|
22
|
+
starting it up again so, I dunno, another device might be able
|
|
23
|
+
to connect and sensor classes could maybe get beacon updates.
|
|
24
|
+
|
|
25
|
+
You know, the little things.
|
|
26
|
+
*/
|
|
27
|
+
adapter.waitDevice(mac,(30000)).then((device) =>{
|
|
28
|
+
|
|
29
|
+
return connectQueue.enqueue( async ()=>{
|
|
30
|
+
console.log("Connecting to "+mac)
|
|
31
|
+
try {await device.connect()} catch {(e)=>console.log(e)}
|
|
32
|
+
try {
|
|
33
|
+
console.log("Connected to "+mac)
|
|
34
|
+
console.log("Stopping discovery for "+mac)
|
|
35
|
+
|
|
36
|
+
await adapter.helper.callMethod('StopDiscovery')
|
|
37
|
+
console.log("Discovery stopped for "+mac)
|
|
38
|
+
await adapter.helper.callMethod('SetDiscoveryFilter', {
|
|
39
|
+
Transport: new Variant('s', "le")
|
|
40
|
+
})
|
|
41
|
+
console.log("Starting discovery for "+mac)
|
|
42
|
+
await adapter.helper.callMethod('StartDiscovery')
|
|
43
|
+
console.log("Discovery started for "+mac)
|
|
44
|
+
|
|
45
|
+
} catch (e){
|
|
46
|
+
//probably ignorable error. probably.
|
|
47
|
+
console.log(e)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
/* END HACK*/
|
|
52
|
+
}
|
|
53
|
+
setInterval( ()=>{
|
|
54
|
+
deviceConnect("D1:06:00:C6:16:4A")
|
|
55
|
+
}, 5000)
|
|
56
|
+
setInterval( ()=>{
|
|
57
|
+
|
|
58
|
+
for (const mac of (["D1:06:01:46:49:39","A4:C1:38:3E:7E:94"])){
|
|
59
|
+
try { deviceConnect(mac) } catch { (e)=>console.log(e) }
|
|
60
|
+
}
|
|
61
|
+
}, 10000)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|