From 1e7542b63271a40ad531fb4458988001531d2387 Mon Sep 17 00:00:00 2001
From: SergeiTarkhanov <genigod@gmail.com>
Date: Fri, 15 Nov 2024 00:09:28 +0300
Subject: [PATCH] Add PeaNUT custom service

---
 docs/customservices.md             | 12 +++++
 src/components/services/PeaNUT.vue | 87 ++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)
 create mode 100644 src/components/services/PeaNUT.vue

diff --git a/docs/customservices.md b/docs/customservices.md
index 733c151..396ce06 100644
--- a/docs/customservices.md
+++ b/docs/customservices.md
@@ -170,6 +170,18 @@ For Prometheus you need to set the type to Prometheus and provide a url.
   # subtitle: "Monitor data server"
 ```
 
+## PeaNUT
+
+This service show current status of the UPS device. By default, the subtitle line shows UPS load, unless you provide the `subtitle` property
+
+```yaml
+- name: "PeaNUT"
+  type: PeaNUT
+  logo: "assets/tools/sample.png"
+  url: "http://192.168.0.151"
+  # device: "ups" # The ID of the device
+```
+
 ## AdGuard Home
 For AdGuard Home you need to set the type to AdGuard, if you have some issues as 403 responses on requests you need to provide authentication in headers for locations needed as below.
 
diff --git a/src/components/services/PeaNUT.vue b/src/components/services/PeaNUT.vue
new file mode 100644
index 0000000..62cd6d4
--- /dev/null
+++ b/src/components/services/PeaNUT.vue
@@ -0,0 +1,87 @@
+<template>
+  <Generic :item="item">
+    <template #content>
+      <p class="title is-4">{{ item.name }}</p>
+      <p class="subtitle is-6">
+        <template v-if="item.subtitle">
+          {{ item.subtitle }}
+        </template>
+        <template v-else-if="load">
+          {{ load }}&percnt; UPS Load
+        </template>
+      </p>
+    </template>
+    <template #indicator>
+      <div v-if="ups_status" class="status" :class="status_class">
+        {{ status_text }}
+      </div>
+    </template>
+  </Generic>
+</template>
+
+<script>
+import service from "@/mixins/service.js";
+import Generic from "./Generic.vue";
+
+export default {
+  name: "PeaNUT",
+  components: {
+    Generic,
+  },
+  mixins: [service],
+  props: {
+    item: Object,
+  },
+  data: () => ({
+    ups_status: "",
+    ups_load: 0,
+  }),
+  computed: {
+    status_text: function () {
+      switch (this.ups_status) {
+        case "OL":
+          return "online";
+        case "OB":
+          return "on battery"
+        case "LB":
+          return "low battery";
+        default:
+          return "unknown";
+      }
+    },
+    status_class: function () {
+      switch (this.ups_status) {
+        case "OL":
+          return "online";
+        case "OB": // On battery
+          return "pending"
+        case "LB": // Low battery
+          return "offline";
+        default:
+          return "unknown";
+      }
+    },
+    load: function () {
+      if (this.ups_load) {
+        return this.ups_load.toFixed(1);
+      }
+      return "";
+    },
+  },
+  created() {
+    this.fetchStatus();
+  },
+  methods: {
+    fetchStatus: async function () {
+      const device = this.item.device || '';
+
+      const result = await this.fetch(`/api/v1/devices/${device}`).catch((e) =>
+        console.log(e),
+      );
+
+      this.ups_status = result["ups.status"] || "";
+      this.ups_load = result["ups.load"] || 0;
+    },
+  },
+};
+</script>