Skip to content

Commit

Permalink
Merge pull request #9 from Tom-Hirschberger/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Tom-Hirschberger authored Nov 17, 2022
2 parents d5d082c + ab6c755 commit 81c201a
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 12 deletions.
135 changes: 127 additions & 8 deletions MMM-TouchButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ Module.register('MMM-TouchButton', {
classes: null,
buttons: [],
addEmptyTitle: false,
buttons: []
buttons: [],
refreshOnNotification: true,
refreshOnlyIfValueChanged: true,
notificationDelay: 3000,
notificationsAtStart: []
},

getScripts: function () {
return [this.file('node_modules/js-uuid/js-uuid.js'), this.file('node_modules/@iconify/iconify/dist/iconify.min.js')];
return [this.file('node_modules/jsonpath-plus/dist/index-browser-umd.js'), this.file('node_modules/js-uuid/js-uuid.js'), this.file('node_modules/@iconify/iconify/dist/iconify.min.js')];
},

getStyles: function() {
Expand Down Expand Up @@ -57,13 +61,23 @@ Module.register('MMM-TouchButton', {
for (let curCondition of buttonConfig["conditions"]){
let source = curCondition["source"] || null
let type = curCondition["type"] || null
let value = curCondition["value"] || null
let value = null
if (typeof curCondition["value"] !== "undefined"){
value = curCondition["value"]
}
let jsonpath = curCondition["jsonpath"] || null

if((source != null) && (type != null) && (value != null)){
let curSource = buttonResults[source]
let curSource
if(jsonpath != null){
curSource = buttonResults[source+jsonpath]
} else {
curSource = buttonResults[source]
}

if(curSource != null){
if(self.validateCondition(curSource, value, type)){
let valResult = self.validateCondition(curSource, value, type)
if(valResult){
icon = curCondition["icon"] || icon
imgIcon = curCondition["imgIcon"] || imgIcon
classes = []
Expand Down Expand Up @@ -137,8 +151,11 @@ Module.register('MMM-TouchButton', {
curButton.classList.add("icon")
} else {
curButton = document.createElement("span")
curButton.classList.add("iconify-inline")
curButton.setAttribute("data-icon", curCondButtonConfig[0])
curButton.classList.add("iconify")
curButtonIconWrapper = document.createElement("span")
curButtonIconWrapper.classList.add("iconify-inline")
curButtonIconWrapper.setAttribute("data-icon", curCondButtonConfig[0])
curButton.appendChild(curButtonIconWrapper)
}
}

Expand All @@ -163,14 +180,116 @@ Module.register('MMM-TouchButton', {
self.sendSocketNotification('CONFIG', [self.moduleId, self.config])
self.results = {}
self.currentProfile = null
self.notifications = {}
self.watchNotifications = false
for(let curBtnId = 0; curBtnId < self.config.buttons.length; curBtnId++){
let curButtonConfig = self.config.buttons[curBtnId]
let curConditions = curButtonConfig["conditions"] || null
if (curConditions != null){
for (let curCondId = 0; curCondId < curConditions.length; curCondId++){
let curSource = curConditions[curCondId].source || null

if((curSource != null) && (curSource != "out") && (curSource != "err") && (curSource != "code")){
let curNotiObj = self.notifications[curSource] || []
let curResObj = {}
curResObj["id"] = curBtnId
curResObj["condition"] = curConditions[curCondId]
curNotiObj.push(curResObj)
self.notifications[curSource] = curNotiObj
self.watchNotifications = true
}
}
}
}

setTimeout(()=>{
for (let curNotiId = 0; curNotiId < self.config.notificationsAtStart.length; curNotiId++){
let curNotiObj = self.config.notificationsAtStart[curNotiId]
if (curNotiObj.length > 1){
self.sendNotification(curNotiObj[0], curNotiObj[1])
} else {
self.sendNotification(curNotiObj[0])
}
}
}, self.config.notificationDelay)
},

//https://stackoverflow.com/questions/3710204/how-to-check-if-a-string-is-a-valid-json-string
tryParseJSONObject: function (jsonString) {
try {
var o = JSON.parse(jsonString);

// Handle non-exception-throwing cases:
// Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
// but... JSON.parse(null) returns null, and typeof null === "object",
// so we must check for that, too. Thankfully, null is falsey, so this suffices:
if (o && typeof o === "object") {
return o;
}
}
catch (e) { }

return false;
},

notificationReceived: function (notification, payload) {
const self = this
if (notification === "CHANGED_PROFILE") {
self.currentProfile = payload.to
self.updateDom(self.config.animationSpeed)
}
}

if(self.watchNotifications){
if (typeof self.notifications[notification] !== "undefined"){
let refreshNeeded = false
let curNotificationUsers = self.notifications[notification]
for(let curCondBtnIdx = 0; curCondBtnIdx < curNotificationUsers.length; curCondBtnIdx++){
let curId = curNotificationUsers[curCondBtnIdx].id
let curCondition = curNotificationUsers[curCondBtnIdx].condition
let curJsonpath = curCondition.jsonpath || null
let curResult

if (curJsonpath != null) {
let curParsedPayload = self.tryParseJSONObject(payload)
if(curParsedPayload){
curResult = JSONPath.JSONPath({ path: curJsonpath, json: curParsedPayload })[0];
} else {
curResult = payload
}
} else {
curResult = payload
}

let curResultExtendedNotification = notification
if (curJsonpath != null){
curResultExtendedNotification += curJsonpath
}

let oldResultObj = self.results[curId] || null

let oldResult = null
if(oldResultObj != null){
oldResult = oldResultObj[curResultExtendedNotification] || null
} else {
oldResultObj = {}
}

if (oldResult !== curResult) {
oldResultObj[curResultExtendedNotification] = curResult
self.results[curId] = oldResultObj
refreshNeeded = true
} else {
if (!self.config.refreshOnlyIfValueChanged) {
refreshNeeded = true
}
}
}

if(refreshNeeded){
self.updateDom(self.config.animationSpeed)
}
}
}
},

socketNotificationReceived: function (notification, payload) {
Expand Down
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ An example with three buttons. One to shutdown the host, one to reboot it and on
| classes | A space separted String of CSS classes that should be added to the wrapper classes. If you use mulitiple instances of the module you can style them differently by added different classes. | String like "myClass1 myClass2 | null |
| addEmptyTitle | If titles are used for some buttons this option makes it possible to add empty title dummys to all buttons without title | Boolean | false |
| buttons | The array containing an object for each button | Array [] | [] |
| refreshOnNotification | If conditions which use the payload of notifications as type the modules content gets refreshed if one of these notifications is received. | Boolean | true |
| refreshOnlyIfValueChanged | Normally the module gets refreshed if one of the conditional notifications gets received. If "refreshOnlyIfValueChanged" is set to true the module only gets refreshed if the payload of the notification changed to the last refresh. | Boolean | true |
| notificationsAtStart | If the module should send some notifications after the startup the can be configured in this array. The array should contain a array of for each notification. The first element is the name, the second one the payload. The payload is optional. (i.e. notificationsAtStart: [["dummyOne"], ["dummyTwo", "dummyPayload"]]). | Array | [] |
| notificationDelay | The notifications configured with notificationsAtStart will be send after this amout of milliseconds after the module got started. | Integer | 3000 |

### Buttons

Expand All @@ -101,7 +105,7 @@ An example with three buttons. One to shutdown the host, one to reboot it and on

### Conditions

The module can be configured to display different icons or change the css classes added to the button elements based on the output or return codes of the commands.
The module can be configured to display different icons or change the css classes added to the button elements based on the output or return codes of the commands or the payload of received notifications.

The conditions array contains objects that specify what to check against which values.

Expand All @@ -122,9 +126,12 @@ The following sources are possible:
* "out" which is the standard out stream (normal output) of the command
* "err" which is the error stream of the command
* "code" which is the return code of the command (unix style is to return 0 if everything is fine and anything else if a problem occured)
* Any other type will be interpreted as the name of a notification

And we need a value to compare to which is configured with the "value" option.

If the value is a valid JSON object you can use [jsonpath-plus](https://github.com/JSONPath-Plus/JSONPath) to search for a specific element (only the first one which matches the [jsonpath-plus](https://github.com/JSONPath-Plus/JSONPath) expression is used).

#### Example

Lets look at this example now:
Expand All @@ -141,7 +148,22 @@ Lets look at this example now:
classes: "up_1",
icon: "fa fa-circle-o",
notification: "USER_PRESENCE",
payload: true
payload: true,
conditions: [
{
source: "MY_DUMMY_NOTIFICATION",
type: "eq",
value: "dummy_payload",
icon: "ic:baseline-lightbulb"
},
{
source: "MY_DUMMY_NOTIFICATION_TWO",
type: "eq",
value: true,
jsonpath: "output"
icon: "fa fa-bath"
}
]
},
{
name: "Test",
Expand Down Expand Up @@ -198,6 +220,7 @@ In this example two instances of the module will be added at "top_center" and "t
* The elements get the html class "up_1" added
* The icon will be "fa fa-circle-o"
* If the button gets pressed the notification "USER_PRESENCE" with the payload "true" will be send
* If a notification "MY_DUMMY_NOTIFICATION" with value "dummy_payload" is received by the module the icon "ic:baseline-lightbulb" is used instead of the normal icon "fa fa-circle-o". If the "MY_DUMMY_NOTIFICATION_TWO" notification is received with a JSON object as payload that contains the path "output" (i.e. {"output": false, "notNeeded": 123}) the icon "fa fa-bath" is used.
* Button with name "Test"
* The icon "fluent-emoji:test-tube" will be used (but not if the first conditions matches)
* The command "./test.bash" will be called with the first argument set to "0"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "MMM-TouchButton",
"version": "0.0.4",
"version": "0.0.5",
"description": "",
"main": "MMM-TouchButton",
"dependencies": {
"js-uuid": "latest",
"jsonpath-plus": "5.0.1",
"@iconify/iconify": "latest"
},
"devDependencies": {},
Expand Down
2 changes: 1 addition & 1 deletion touch-button.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
margin: 5px;
}

.MMM-TouchButton .touchButton .button.iconify{
.MMM-TouchButton .touchButton .button .iconify-inline{
width: 20px;
height: 20px;
margin: 5px;
Expand Down

0 comments on commit 81c201a

Please sign in to comment.