Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
78
plugins/inputs/fibaro/README.md
Normal file
78
plugins/inputs/fibaro/README.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Fibaro Input Plugin
|
||||
|
||||
This plugin gathers data from devices connected to a [Fibaro][fibaro]
|
||||
controller. Those values could be true (1) or false (0) for switches, percentage
|
||||
for dimmers, temperature, etc. Both _Home Center 2_ and _Home Center 3_ devices
|
||||
are supported.
|
||||
|
||||
⭐ Telegraf v1.7.0
|
||||
🏷️ iot
|
||||
💻 all
|
||||
|
||||
[fibaro]: https://www.fibaro.com
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Read devices value(s) from a Fibaro controller
|
||||
[[inputs.fibaro]]
|
||||
## Required Fibaro controller address/hostname.
|
||||
## Note: at the time of writing this plugin, Fibaro only implemented http - no https available
|
||||
url = "http://<controller>:80"
|
||||
|
||||
## Required credentials to access the API (http://<controller/api/<component>)
|
||||
username = "<username>"
|
||||
password = "<password>"
|
||||
|
||||
## Amount of time allowed to complete the HTTP request
|
||||
# timeout = "5s"
|
||||
|
||||
## Fibaro Device Type
|
||||
## By default, this plugin will attempt to read using the HC2 API. For HC3
|
||||
## devices, set this to "HC3"
|
||||
# device_type = "HC2"
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
- fibaro
|
||||
- tags:
|
||||
- deviceId (device id)
|
||||
- section (section name)
|
||||
- room (room name)
|
||||
- name (device name)
|
||||
- type (device type)
|
||||
- fields:
|
||||
- batteryLevel (float, when available from device)
|
||||
- energy (float, when available from device)
|
||||
- power (float, when available from device)
|
||||
- value (float)
|
||||
- value2 (float, when available from device)
|
||||
|
||||
## Example Output
|
||||
|
||||
```text
|
||||
fibaro,deviceId=9,host=vm1,name=Fenêtre\ haute,room=Cuisine,section=Cuisine,type=com.fibaro.FGRM222 energy=2.04,power=0.7,value=99,value2=99 1529996807000000000
|
||||
fibaro,deviceId=10,host=vm1,name=Escaliers,room=Dégagement,section=Pièces\ communes,type=com.fibaro.binarySwitch value=0 1529996807000000000
|
||||
fibaro,deviceId=13,host=vm1,name=Porte\ fenêtre,room=Salon,section=Pièces\ communes,type=com.fibaro.FGRM222 energy=4.33,power=0.7,value=99,value2=99 1529996807000000000
|
||||
fibaro,deviceId=21,host=vm1,name=LED\ îlot\ central,room=Cuisine,section=Cuisine,type=com.fibaro.binarySwitch value=0 1529996807000000000
|
||||
fibaro,deviceId=90,host=vm1,name=Détérioration,room=Entrée,section=Pièces\ communes,type=com.fibaro.heatDetector value=0 1529996807000000000
|
||||
fibaro,deviceId=163,host=vm1,name=Température,room=Cave,section=Cave,type=com.fibaro.temperatureSensor value=21.62 1529996807000000000
|
||||
fibaro,deviceId=191,host=vm1,name=Présence,room=Garde-manger,section=Cuisine,type=com.fibaro.FGMS001 value=1 1529996807000000000
|
||||
fibaro,deviceId=193,host=vm1,name=Luminosité,room=Garde-manger,section=Cuisine,type=com.fibaro.lightSensor value=195 1529996807000000000
|
||||
fibaro,deviceId=200,host=vm1,name=Etat,room=Garage,section=Extérieur,type=com.fibaro.doorSensor value=0 1529996807000000000
|
||||
fibaro,deviceId=220,host=vm1,name=CO2\ (ppm),room=Salon,section=Pièces\ communes,type=com.fibaro.multilevelSensor value=536 1529996807000000000
|
||||
fibaro,deviceId=221,host=vm1,name=Humidité\ (%),room=Salon,section=Pièces\ communes,type=com.fibaro.humiditySensor value=61 1529996807000000000
|
||||
fibaro,deviceId=222,host=vm1,name=Pression\ (mb),room=Salon,section=Pièces\ communes,type=com.fibaro.multilevelSensor value=1013.7 1529996807000000000
|
||||
fibaro,deviceId=223,host=vm1,name=Bruit\ (db),room=Salon,section=Pièces\ communes,type=com.fibaro.multilevelSensor value=44 1529996807000000000
|
||||
fibaro,deviceId=248,host=vm1,name=Température,room=Garage,section=Extérieur,type=com.fibaro.temperatureSensor batteryLevel=85,value=10.8 1529996807000000000
|
||||
```
|
123
plugins/inputs/fibaro/fibaro.go
Normal file
123
plugins/inputs/fibaro/fibaro.go
Normal file
|
@ -0,0 +1,123 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package fibaro
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"github.com/influxdata/telegraf/plugins/inputs/fibaro/hc2"
|
||||
"github.com/influxdata/telegraf/plugins/inputs/fibaro/hc3"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const defaultTimeout = 5 * time.Second
|
||||
|
||||
type Fibaro struct {
|
||||
URL string `toml:"url"`
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
Timeout config.Duration `toml:"timeout"`
|
||||
DeviceType string `toml:"device_type"`
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (*Fibaro) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (f *Fibaro) Init() error {
|
||||
switch f.DeviceType {
|
||||
case "":
|
||||
f.DeviceType = "HC2"
|
||||
case "HC2", "HC3":
|
||||
default:
|
||||
return errors.New("invalid option for device type")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Fibaro) Gather(acc telegraf.Accumulator) error {
|
||||
if f.client == nil {
|
||||
f.client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
},
|
||||
Timeout: time.Duration(f.Timeout),
|
||||
}
|
||||
}
|
||||
|
||||
sections, err := f.getJSON("/api/sections")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rooms, err := f.getJSON("/api/rooms")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
devices, err := f.getJSON("/api/devices")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch f.DeviceType {
|
||||
case "HC2":
|
||||
return hc2.Parse(acc, sections, rooms, devices)
|
||||
case "HC3":
|
||||
return hc3.Parse(acc, sections, rooms, devices)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getJSON connects, authenticates and reads JSON payload returned by Fibaro box
|
||||
func (f *Fibaro) getJSON(path string) ([]byte, error) {
|
||||
var requestURL = f.URL + path
|
||||
|
||||
req, err := http.NewRequest("GET", requestURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.SetBasicAuth(f.Username, f.Password)
|
||||
resp, err := f.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = fmt.Errorf("response from url %q has status code %d (%s), expected %d (%s)",
|
||||
requestURL,
|
||||
resp.StatusCode,
|
||||
http.StatusText(resp.StatusCode),
|
||||
http.StatusOK,
|
||||
http.StatusText(http.StatusOK))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read response body: %w", err)
|
||||
}
|
||||
|
||||
return bodyBytes, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("fibaro", func() telegraf.Input {
|
||||
return &Fibaro{
|
||||
Timeout: config.Duration(defaultTimeout),
|
||||
}
|
||||
})
|
||||
}
|
306
plugins/inputs/fibaro/fibaro_test.go
Normal file
306
plugins/inputs/fibaro/fibaro_test.go
Normal file
|
@ -0,0 +1,306 @@
|
|||
package fibaro
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
// TestUnauthorized validates that 401 (wrong credentials) is managed properly
|
||||
func TestUnauthorized(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
a := Fibaro{
|
||||
URL: ts.URL,
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
client: &http.Client{},
|
||||
}
|
||||
require.NoError(t, a.Init())
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
// TestJSONSuccess validates that module works OK with valid JSON payloads
|
||||
func TestJSONSuccess(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
payload := ""
|
||||
switch r.URL.Path {
|
||||
case "/api/sections":
|
||||
content, err := os.ReadFile(path.Join("testdata", "sections.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
case "/api/rooms":
|
||||
content, err := os.ReadFile(path.Join("testdata", "rooms.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
case "/api/devices":
|
||||
content, err := os.ReadFile(path.Join("testdata", "device_hc2.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := fmt.Fprintln(w, payload); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
a := Fibaro{
|
||||
URL: ts.URL,
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
client: &http.Client{},
|
||||
}
|
||||
require.NoError(t, a.Init())
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(5), acc.NMetrics())
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "1",
|
||||
"section": "Section 1",
|
||||
"room": "Room 1",
|
||||
"name": "Device 1",
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(0),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "2",
|
||||
"section": "Section 2",
|
||||
"room": "Room 2",
|
||||
"name": "Device 2",
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(1),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "3",
|
||||
"section": "Section 3",
|
||||
"room": "Room 3",
|
||||
"name": "Device 3",
|
||||
"type": "com.fibaro.multilevelSwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(67),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "4",
|
||||
"section": "Section 3",
|
||||
"room": "Room 4",
|
||||
"name": "Device 4",
|
||||
"type": "com.fibaro.temperatureSensor",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"batteryLevel": float64(100),
|
||||
"value": float64(22.8),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "5",
|
||||
"section": "Section 3",
|
||||
"room": "Room 4",
|
||||
"name": "Device 5",
|
||||
"type": "com.fibaro.FGRM222",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"energy": float64(4.33),
|
||||
"power": float64(0.7),
|
||||
"value": float64(50),
|
||||
"value2": float64(75),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestHC3JSON(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
payload := ""
|
||||
switch r.URL.Path {
|
||||
case "/api/sections":
|
||||
content, err := os.ReadFile(path.Join("testdata", "sections.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
case "/api/rooms":
|
||||
content, err := os.ReadFile(path.Join("testdata", "rooms.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
case "/api/devices":
|
||||
content, err := os.ReadFile(path.Join("testdata", "device_hc3.json"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
payload = string(content)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := fmt.Fprintln(w, payload); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
a := Fibaro{
|
||||
URL: ts.URL,
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
DeviceType: "HC3",
|
||||
client: &http.Client{},
|
||||
}
|
||||
require.NoError(t, a.Init())
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := acc.GatherError(a.Gather)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(5), acc.NMetrics())
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "1",
|
||||
"section": "Section 1",
|
||||
"room": "Room 1",
|
||||
"name": "Device 1",
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(0),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "2",
|
||||
"section": "Section 2",
|
||||
"room": "Room 2",
|
||||
"name": "Device 2",
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(1),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "3",
|
||||
"section": "Section 3",
|
||||
"room": "Room 3",
|
||||
"name": "Device 3",
|
||||
"type": "com.fibaro.multilevelSwitch",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"value": float64(67),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "4",
|
||||
"section": "Section 3",
|
||||
"room": "Room 4",
|
||||
"name": "Device 4",
|
||||
"type": "com.fibaro.temperatureSensor",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"batteryLevel": float64(100),
|
||||
"value": float64(22.8),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"fibaro",
|
||||
map[string]string{
|
||||
"deviceId": "5",
|
||||
"section": "Section 3",
|
||||
"room": "Room 4",
|
||||
"name": "Device 5",
|
||||
"type": "com.fibaro.FGRM222",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"energy": float64(4.33),
|
||||
"power": float64(0.7),
|
||||
"value": float64(34),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestInvalidDeviceType(t *testing.T) {
|
||||
a := Fibaro{
|
||||
DeviceType: "foobar",
|
||||
}
|
||||
require.Error(t, a.Init())
|
||||
}
|
96
plugins/inputs/fibaro/hc2/parser.go
Normal file
96
plugins/inputs/fibaro/hc2/parser.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package hc2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
)
|
||||
|
||||
// Parse parses data from sections, rooms and devices, and adds measurements containing parsed data.
|
||||
func Parse(acc telegraf.Accumulator, sectionBytes, roomBytes, devicesBytes []byte) error {
|
||||
var tmpSections []Sections
|
||||
if err := json.Unmarshal(sectionBytes, &tmpSections); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sections := make(map[uint16]string, len(tmpSections))
|
||||
for _, v := range tmpSections {
|
||||
sections[v.ID] = v.Name
|
||||
}
|
||||
|
||||
var tmpRooms []Rooms
|
||||
if err := json.Unmarshal(roomBytes, &tmpRooms); err != nil {
|
||||
return err
|
||||
}
|
||||
rooms := make(map[uint16]LinkRoomsSections, len(tmpRooms))
|
||||
for _, v := range tmpRooms {
|
||||
rooms[v.ID] = LinkRoomsSections{Name: v.Name, SectionID: v.SectionID}
|
||||
}
|
||||
|
||||
var devices []Devices
|
||||
if err := json.Unmarshal(devicesBytes, &devices); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, device := range devices {
|
||||
// skip device in some cases
|
||||
if device.RoomID == 0 ||
|
||||
!device.Enabled ||
|
||||
device.Properties.Dead == "true" ||
|
||||
device.Type == "com.fibaro.zwaveDevice" {
|
||||
continue
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"deviceId": strconv.FormatUint(uint64(device.ID), 10),
|
||||
"section": sections[rooms[device.RoomID].SectionID],
|
||||
"room": rooms[device.RoomID].Name,
|
||||
"name": device.Name,
|
||||
"type": device.Type,
|
||||
}
|
||||
fields := make(map[string]interface{})
|
||||
|
||||
if device.Properties.BatteryLevel != nil {
|
||||
if fValue, err := strconv.ParseFloat(*device.Properties.BatteryLevel, 64); err == nil {
|
||||
fields["batteryLevel"] = fValue
|
||||
}
|
||||
}
|
||||
|
||||
if device.Properties.Energy != nil {
|
||||
if fValue, err := strconv.ParseFloat(*device.Properties.Energy, 64); err == nil {
|
||||
fields["energy"] = fValue
|
||||
}
|
||||
}
|
||||
|
||||
if device.Properties.Power != nil {
|
||||
if fValue, err := strconv.ParseFloat(*device.Properties.Power, 64); err == nil {
|
||||
fields["power"] = fValue
|
||||
}
|
||||
}
|
||||
|
||||
if device.Properties.Value != nil {
|
||||
value := device.Properties.Value
|
||||
switch value {
|
||||
case "true":
|
||||
value = "1"
|
||||
case "false":
|
||||
value = "0"
|
||||
}
|
||||
|
||||
if fValue, err := strconv.ParseFloat(value.(string), 64); err == nil {
|
||||
fields["value"] = fValue
|
||||
}
|
||||
}
|
||||
|
||||
if device.Properties.Value2 != nil {
|
||||
if fValue, err := strconv.ParseFloat(*device.Properties.Value2, 64); err == nil {
|
||||
fields["value2"] = fValue
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddFields("fibaro", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
37
plugins/inputs/fibaro/hc2/types.go
Normal file
37
plugins/inputs/fibaro/hc2/types.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package hc2
|
||||
|
||||
// LinkRoomsSections links rooms to sections
|
||||
type LinkRoomsSections struct {
|
||||
Name string
|
||||
SectionID uint16
|
||||
}
|
||||
|
||||
// Sections contains sections information
|
||||
type Sections struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Rooms contains rooms information
|
||||
type Rooms struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SectionID uint16 `json:"sectionID"`
|
||||
}
|
||||
|
||||
// Devices contains devices information
|
||||
type Devices struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RoomID uint16 `json:"roomID"`
|
||||
Type string `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Properties struct {
|
||||
BatteryLevel *string `json:"batteryLevel"`
|
||||
Dead string `json:"dead"`
|
||||
Energy *string `json:"energy"`
|
||||
Power *string `json:"power"`
|
||||
Value interface{} `json:"value"`
|
||||
Value2 *string `json:"value2"`
|
||||
} `json:"properties"`
|
||||
}
|
81
plugins/inputs/fibaro/hc3/parser.go
Normal file
81
plugins/inputs/fibaro/hc3/parser.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
package hc3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
)
|
||||
|
||||
// Parse parses data from sections, rooms and devices, and adds measurements containing parsed data.
|
||||
func Parse(acc telegraf.Accumulator, sectionBytes, roomBytes, devicesBytes []byte) error {
|
||||
var tmpSections []Sections
|
||||
if err := json.Unmarshal(sectionBytes, &tmpSections); err != nil {
|
||||
return err
|
||||
}
|
||||
sections := make(map[uint16]string, len(tmpSections))
|
||||
for _, v := range tmpSections {
|
||||
sections[v.ID] = v.Name
|
||||
}
|
||||
|
||||
var tmpRooms []Rooms
|
||||
if err := json.Unmarshal(roomBytes, &tmpRooms); err != nil {
|
||||
return err
|
||||
}
|
||||
rooms := make(map[uint16]linkRoomsSections, len(tmpRooms))
|
||||
for _, v := range tmpRooms {
|
||||
rooms[v.ID] = linkRoomsSections{Name: v.Name, SectionID: v.SectionID}
|
||||
}
|
||||
|
||||
var devices []Devices
|
||||
if err := json.Unmarshal(devicesBytes, &devices); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, device := range devices {
|
||||
// skip device in some cases
|
||||
if device.RoomID == 0 ||
|
||||
!device.Enabled ||
|
||||
device.Properties.Dead ||
|
||||
device.Type == "com.fibaro.zwaveDevice" {
|
||||
continue
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"deviceId": strconv.FormatUint(uint64(device.ID), 10),
|
||||
"section": sections[rooms[device.RoomID].SectionID],
|
||||
"room": rooms[device.RoomID].Name,
|
||||
"name": device.Name,
|
||||
"type": device.Type,
|
||||
}
|
||||
fields := make(map[string]interface{})
|
||||
|
||||
if device.Properties.BatteryLevel != nil {
|
||||
fields["batteryLevel"] = *device.Properties.BatteryLevel
|
||||
}
|
||||
|
||||
if device.Properties.Energy != nil {
|
||||
fields["energy"] = *device.Properties.Energy
|
||||
}
|
||||
|
||||
if device.Properties.Power != nil {
|
||||
fields["power"] = *device.Properties.Power
|
||||
}
|
||||
|
||||
// Value can be a JSON bool, string, or numeric value
|
||||
if device.Properties.Value != nil {
|
||||
v, err := internal.ToFloat64(device.Properties.Value)
|
||||
if err != nil {
|
||||
acc.AddError(fmt.Errorf("unable to convert value: %w", err))
|
||||
} else {
|
||||
fields["value"] = v
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddFields("fibaro", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
37
plugins/inputs/fibaro/hc3/types.go
Normal file
37
plugins/inputs/fibaro/hc3/types.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package hc3
|
||||
|
||||
// LinkRoomsSections links rooms to sections
|
||||
type linkRoomsSections struct {
|
||||
Name string
|
||||
SectionID uint16
|
||||
}
|
||||
|
||||
// Sections contains sections information
|
||||
type Sections struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Rooms contains rooms information
|
||||
type Rooms struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SectionID uint16 `json:"sectionID"`
|
||||
}
|
||||
|
||||
// Devices contains devices information
|
||||
type Devices struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RoomID uint16 `json:"roomID"`
|
||||
Type string `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Properties struct {
|
||||
BatteryLevel *float64 `json:"batteryLevel"`
|
||||
Dead bool `json:"dead"`
|
||||
Energy *float64 `json:"energy"`
|
||||
Power *float64 `json:"power"`
|
||||
Value interface{} `json:"value"`
|
||||
Value2 *string `json:"value2"`
|
||||
} `json:"properties"`
|
||||
}
|
17
plugins/inputs/fibaro/sample.conf
Normal file
17
plugins/inputs/fibaro/sample.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Read devices value(s) from a Fibaro controller
|
||||
[[inputs.fibaro]]
|
||||
## Required Fibaro controller address/hostname.
|
||||
## Note: at the time of writing this plugin, Fibaro only implemented http - no https available
|
||||
url = "http://<controller>:80"
|
||||
|
||||
## Required credentials to access the API (http://<controller/api/<component>)
|
||||
username = "<username>"
|
||||
password = "<password>"
|
||||
|
||||
## Amount of time allowed to complete the HTTP request
|
||||
# timeout = "5s"
|
||||
|
||||
## Fibaro Device Type
|
||||
## By default, this plugin will attempt to read using the HC2 API. For HC3
|
||||
## devices, set this to "HC3"
|
||||
# device_type = "HC2"
|
66
plugins/inputs/fibaro/testdata/device_hc2.json
vendored
Normal file
66
plugins/inputs/fibaro/testdata/device_hc2.json
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Device 1",
|
||||
"roomID": 1,
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": "false",
|
||||
"value": "false"
|
||||
},
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Device 2",
|
||||
"roomID": 2,
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": "false",
|
||||
"value": "true"
|
||||
},
|
||||
"sortOrder": 2
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Device 3",
|
||||
"roomID": 3,
|
||||
"type": "com.fibaro.multilevelSwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": "false",
|
||||
"value": "67"
|
||||
},
|
||||
"sortOrder": 3
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Device 4",
|
||||
"roomID": 4,
|
||||
"type": "com.fibaro.temperatureSensor",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"batteryLevel": "100",
|
||||
"dead": "false",
|
||||
"value": "22.80"
|
||||
},
|
||||
"sortOrder": 4
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Device 5",
|
||||
"roomID": 4,
|
||||
"type": "com.fibaro.FGRM222",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"energy": "4.33",
|
||||
"power": "0.7",
|
||||
"dead": "false",
|
||||
"value": "50",
|
||||
"value2": "75"
|
||||
},
|
||||
"sortOrder": 5
|
||||
}
|
||||
]
|
65
plugins/inputs/fibaro/testdata/device_hc3.json
vendored
Normal file
65
plugins/inputs/fibaro/testdata/device_hc3.json
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Device 1",
|
||||
"roomID": 1,
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": false,
|
||||
"value": false
|
||||
},
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Device 2",
|
||||
"roomID": 2,
|
||||
"type": "com.fibaro.binarySwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": false,
|
||||
"value": true
|
||||
},
|
||||
"sortOrder": 2
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Device 3",
|
||||
"roomID": 3,
|
||||
"type": "com.fibaro.multilevelSwitch",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"dead": false,
|
||||
"value": "67"
|
||||
},
|
||||
"sortOrder": 3
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Device 4",
|
||||
"roomID": 4,
|
||||
"type": "com.fibaro.temperatureSensor",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"batteryLevel": 100,
|
||||
"dead": false,
|
||||
"value": 22.80
|
||||
},
|
||||
"sortOrder": 4
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Device 5",
|
||||
"roomID": 4,
|
||||
"type": "com.fibaro.FGRM222",
|
||||
"enabled": true,
|
||||
"properties": {
|
||||
"energy": 4.33,
|
||||
"power": 0.7,
|
||||
"dead": false,
|
||||
"value": 34
|
||||
},
|
||||
"sortOrder": 5
|
||||
}
|
||||
]
|
30
plugins/inputs/fibaro/testdata/rooms.json
vendored
Normal file
30
plugins/inputs/fibaro/testdata/rooms.json
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Room 1",
|
||||
"sectionID": 1,
|
||||
"icon": "room_1",
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Room 2",
|
||||
"sectionID": 2,
|
||||
"icon": "room_2",
|
||||
"sortOrder": 2
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Room 3",
|
||||
"sectionID": 3,
|
||||
"icon": "room_3",
|
||||
"sortOrder": 3
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Room 4",
|
||||
"sectionID": 3,
|
||||
"icon": "room_4",
|
||||
"sortOrder": 4
|
||||
}
|
||||
]
|
17
plugins/inputs/fibaro/testdata/sections.json
vendored
Normal file
17
plugins/inputs/fibaro/testdata/sections.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Section 1",
|
||||
"sortOrder": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Section 2",
|
||||
"sortOrder": 2
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Section 3",
|
||||
"sortOrder": 3
|
||||
}
|
||||
]
|
Loading…
Add table
Add a link
Reference in a new issue