diff options
-rw-r--r-- | docs/customservices.md | 17 | ||||
-rw-r--r-- | dummy-data/openHAB/rest/systeminfo | 18 | ||||
-rw-r--r-- | src/components/services/OpenHAB.vue | 144 |
3 files changed, 179 insertions, 0 deletions
diff --git a/docs/customservices.md b/docs/customservices.md index 910f401..64ed416 100644 --- a/docs/customservices.md +++ b/docs/customservices.md | |||
@@ -35,6 +35,7 @@ within Homer: | |||
35 | - [Tdarr](#tdarr) | 35 | - [Tdarr](#tdarr) |
36 | - [PiAlert](#pialert) | 36 | - [PiAlert](#pialert) |
37 | - [Immich](#immich) | 37 | - [Immich](#immich) |
38 | - [OpenHAB](#openhab) | ||
38 | 39 | ||
39 | If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page. | 40 | If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page. |
40 | 41 | ||
@@ -446,3 +447,19 @@ The Immich server must be running at least version 1.85.0 for the correct api en | |||
446 | apikey: "<--- Your api key --->" # administrator user | 447 | apikey: "<--- Your api key --->" # administrator user |
447 | updateInterval: 5000 # (Optional) Interval (in ms) for updating the stats | 448 | updateInterval: 5000 # (Optional) Interval (in ms) for updating the stats |
448 | ``` | 449 | ``` |
450 | |||
451 | ## OpenHAB | ||
452 | |||
453 | You need to set the type to OpenHAB, provide an api key and enable cors on OpenHAB. | ||
454 | |||
455 | ```yaml | ||
456 | - name: "OpenHAB" | ||
457 | logo: "assets/tools/sample.png" | ||
458 | url: "http://192.168.0.151/" | ||
459 | type: "OpenHAB" | ||
460 | apikey: "<---insert-api-key-here--->" | ||
461 | things: true # true will query the things API and report total and online things count. false will skip the call | ||
462 | items: true # true will query the items API and report total items count. false will skip the call | ||
463 | ``` | ||
464 | To create an API token on OpenHAB, follow the [official documentation here](https://www.openhab.org/docs/configuration/apitokens.html). | ||
465 | To enable cors on OpenHAB, edit your services/runtime.cfg and uncomment or add this line: `org.openhab.cors:enable=true` \ No newline at end of file | ||
diff --git a/dummy-data/openHAB/rest/systeminfo b/dummy-data/openHAB/rest/systeminfo new file mode 100644 index 0000000..e692cea --- /dev/null +++ b/dummy-data/openHAB/rest/systeminfo | |||
@@ -0,0 +1,18 @@ | |||
1 | { | ||
2 | "systemInfo": { | ||
3 | "configFolder": "/etc/openhab", | ||
4 | "userdataFolder": "/var/lib/openhab", | ||
5 | "logFolder": "/var/log/openhab", | ||
6 | "javaVersion": "17.0.9", | ||
7 | "javaVendor": "Azul Systems, Inc.", | ||
8 | "javaVendorVersion": "Zulu17.46+19-CA", | ||
9 | "osName": "Linux", | ||
10 | "osVersion": "6.5.11-4-pve", | ||
11 | "osArchitecture": "amd64", | ||
12 | "availableProcessors": 2, | ||
13 | "freeMemory": 75885968, | ||
14 | "totalMemory": 494927872, | ||
15 | "uptime": 2150186, | ||
16 | "startLevel": 100 | ||
17 | } | ||
18 | } \ No newline at end of file | ||
diff --git a/src/components/services/OpenHAB.vue b/src/components/services/OpenHAB.vue new file mode 100644 index 0000000..03b50b2 --- /dev/null +++ b/src/components/services/OpenHAB.vue | |||
@@ -0,0 +1,144 @@ | |||
1 | <template> | ||
2 | <Generic :item="item"> | ||
3 | <template #content> | ||
4 | <p class="title is-4">{{ item.name }}</p> | ||
5 | <p class="subtitle is-6"> | ||
6 | <template v-if="item.subtitle"> | ||
7 | {{ item.subtitle }} | ||
8 | </template> | ||
9 | <template v-else> | ||
10 | {{ details }} | ||
11 | </template> | ||
12 | </p> | ||
13 | </template> | ||
14 | <template #indicator> | ||
15 | <div v-if="status" class="status" :class="status"> | ||
16 | {{ status }} | ||
17 | </div> | ||
18 | </template> | ||
19 | </Generic> | ||
20 | </template> | ||
21 | |||
22 | <script> | ||
23 | import service from "@/mixins/service.js"; | ||
24 | import Generic from "./Generic.vue"; | ||
25 | |||
26 | export default { | ||
27 | name: "OpenHAB", | ||
28 | mixins: [service], | ||
29 | props: { | ||
30 | item: Object, | ||
31 | }, | ||
32 | components: { | ||
33 | Generic, | ||
34 | }, | ||
35 | data: () => ({ | ||
36 | status: "", | ||
37 | things: { | ||
38 | count: 0, | ||
39 | online: 0, | ||
40 | }, | ||
41 | items: { | ||
42 | count: 0, | ||
43 | }, | ||
44 | }), | ||
45 | computed: { | ||
46 | headers: function () { | ||
47 | const basicAuth = `${this.item.apikey}:`; | ||
48 | |||
49 | return { | ||
50 | Authorization: `Basic ${btoa(basicAuth)}`, | ||
51 | }; | ||
52 | }, | ||
53 | details: function () { | ||
54 | const details = []; | ||
55 | |||
56 | if (this.item.things) { | ||
57 | details.push( | ||
58 | `${this.things.count} things (${this.things.online} Online)`, | ||
59 | ); | ||
60 | } | ||
61 | |||
62 | if (this.item.items) { | ||
63 | details.push(`${this.items.count} items`); | ||
64 | } | ||
65 | |||
66 | return details.join(", "); | ||
67 | }, | ||
68 | }, | ||
69 | created() { | ||
70 | this.fetchServerStatus(); | ||
71 | |||
72 | if (!this.item.subtitle && this.status !== "dead") { | ||
73 | this.fetchServerStats(); | ||
74 | } | ||
75 | }, | ||
76 | methods: { | ||
77 | fetchServerStatus: async function () { | ||
78 | const headers = this.headers; | ||
79 | this.fetch("/rest/systeminfo", { headers }) | ||
80 | .then((response) => { | ||
81 | if (response && response.systemInfo) this.status = "running"; | ||
82 | else throw new Error(); | ||
83 | }) | ||
84 | .catch((e) => { | ||
85 | console.log(e); | ||
86 | this.status = "dead"; | ||
87 | }); | ||
88 | }, | ||
89 | fetchServerStats: async function () { | ||
90 | const headers = this.headers; | ||
91 | |||
92 | if (this.item.things) { | ||
93 | const data = await this.fetch("/rest/things?summary=true", { | ||
94 | headers, | ||
95 | }).catch((e) => { | ||
96 | console.log(e); | ||
97 | }); | ||
98 | |||
99 | this.things.count = data.length; | ||
100 | this.things.online = data.filter( | ||
101 | (e) => e.statusInfo.status === "ONLINE", | ||
102 | ).length; | ||
103 | } | ||
104 | |||
105 | if (this.item.items) { | ||
106 | const data = await this.fetch("/rest/items", { headers }).catch((e) => { | ||
107 | console.log(e); | ||
108 | }); | ||
109 | |||
110 | this.items.count = data.length; | ||
111 | } | ||
112 | }, | ||
113 | }, | ||
114 | }; | ||
115 | </script> | ||
116 | |||
117 | <style scoped lang="scss"> | ||
118 | .status { | ||
119 | font-size: 0.8rem; | ||
120 | color: var(--text-title); | ||
121 | |||
122 | &.running:before { | ||
123 | background-color: #94e185; | ||
124 | border-color: #78d965; | ||
125 | box-shadow: 0 0 5px 1px #94e185; | ||
126 | } | ||
127 | |||
128 | &.dead:before { | ||
129 | background-color: #c9404d; | ||
130 | border-color: #c42c3b; | ||
131 | box-shadow: 0 0 5px 1px #c9404d; | ||
132 | } | ||
133 | |||
134 | &:before { | ||
135 | content: " "; | ||
136 | display: inline-block; | ||
137 | width: 7px; | ||
138 | height: 7px; | ||
139 | margin-right: 10px; | ||
140 | border: 1px solid #000; | ||
141 | border-radius: 7px; | ||
142 | } | ||
143 | } | ||
144 | </style> | ||