2020-12-22 18:24:23 +01:00
|
|
|
package hue
|
|
|
|
|
|
|
|
import (
|
2020-12-28 17:29:44 +01:00
|
|
|
"encoding/json"
|
2020-12-22 18:24:23 +01:00
|
|
|
"fmt"
|
2020-12-28 17:29:44 +01:00
|
|
|
"io/ioutil"
|
2020-12-22 18:24:23 +01:00
|
|
|
|
|
|
|
"github.com/aexel90/hue_exporter/metric"
|
2020-12-28 17:29:44 +01:00
|
|
|
hueAPI "github.com/amimof/huego"
|
2020-12-22 18:24:23 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Exporter data
|
|
|
|
type Exporter struct {
|
|
|
|
BaseURL string
|
|
|
|
Username string
|
|
|
|
}
|
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
type collectEntry struct {
|
|
|
|
Type string `json:"type"`
|
|
|
|
Result map[string]interface{} `json:"result"`
|
|
|
|
}
|
|
|
|
|
2020-12-22 18:24:23 +01:00
|
|
|
const (
|
2020-12-27 14:58:21 +01:00
|
|
|
TypeLight = "light"
|
2020-12-28 08:49:18 +01:00
|
|
|
TypeSensor = "sensor"
|
2020-12-27 14:58:21 +01:00
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
LabelName = "name"
|
|
|
|
LabelType = "type"
|
|
|
|
LabelID = "id"
|
|
|
|
LabelModelID = "model_id"
|
|
|
|
LabelManufacturerName = "manufacturer_name"
|
|
|
|
LabelSwVersion = "sw_version"
|
|
|
|
LabelSwConfigID = "sw_config_id"
|
|
|
|
LabelUniqueID = "unique_id"
|
|
|
|
|
|
|
|
LabelStateOn = "state_on"
|
|
|
|
LabelStateAlert = "state_alert"
|
|
|
|
LabelStateBri = "state_bri"
|
|
|
|
LabelStateColorMode = "state_color_mode"
|
|
|
|
LabelStateCT = "state_ct"
|
|
|
|
LabelStateReachable = "state_reachable"
|
|
|
|
LabelStateSaturation = "state_saturation"
|
|
|
|
LabelStateButtonEvent = "state_buttonevent"
|
|
|
|
LabelStateDaylight = "state_daylight"
|
|
|
|
LabelStateLastUpdated = "state_lastupdated"
|
|
|
|
LabelStateTemperature = "state_temperature"
|
|
|
|
LabelStateLightLevel = "state_lightlevel"
|
|
|
|
|
|
|
|
LabelConfigBattery = "config_battery"
|
|
|
|
LabelConfigOn = "config_on"
|
|
|
|
LabelConfigReachable = "config_reachable"
|
2020-12-22 18:24:23 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// InitMetrics func
|
|
|
|
func (exporter *Exporter) InitMetrics() (metrics []*metric.Metric) {
|
|
|
|
|
|
|
|
metrics = append(metrics, &metric.Metric{
|
2020-12-28 08:49:18 +01:00
|
|
|
HueType: TypeLight,
|
|
|
|
FqName: "hue_light_info",
|
|
|
|
Help: "Non-numeric data, value is always 1",
|
2020-12-28 17:29:44 +01:00
|
|
|
Labels: []string{
|
|
|
|
LabelName,
|
|
|
|
LabelID,
|
|
|
|
LabelType,
|
|
|
|
LabelModelID,
|
|
|
|
LabelManufacturerName,
|
|
|
|
LabelSwVersion,
|
|
|
|
LabelSwConfigID,
|
|
|
|
LabelUniqueID,
|
|
|
|
LabelStateOn,
|
|
|
|
LabelStateAlert,
|
|
|
|
LabelStateBri,
|
|
|
|
LabelStateCT,
|
|
|
|
LabelStateReachable,
|
|
|
|
LabelStateSaturation,
|
|
|
|
},
|
2020-12-28 08:49:18 +01:00
|
|
|
})
|
2020-12-27 14:58:21 +01:00
|
|
|
|
2020-12-28 12:55:45 +01:00
|
|
|
metrics = append(metrics, &metric.Metric{
|
2020-12-28 17:29:44 +01:00
|
|
|
HueType: TypeLight,
|
|
|
|
FqName: "hue_light_state",
|
|
|
|
Help: "light status (1=ON, 0=OFF)",
|
|
|
|
Labels: []string{
|
|
|
|
LabelName,
|
|
|
|
},
|
2020-12-28 12:55:45 +01:00
|
|
|
ResultKey: LabelStateOn,
|
|
|
|
})
|
|
|
|
|
2020-12-27 14:58:21 +01:00
|
|
|
metrics = append(metrics, &metric.Metric{
|
2020-12-28 08:49:18 +01:00
|
|
|
HueType: TypeSensor,
|
|
|
|
FqName: "hue_sensor_info",
|
|
|
|
Help: "Non-numeric data, value is always 1",
|
2020-12-28 17:29:44 +01:00
|
|
|
Labels: []string{
|
|
|
|
LabelName,
|
|
|
|
LabelID,
|
|
|
|
LabelType,
|
|
|
|
LabelModelID,
|
|
|
|
LabelManufacturerName,
|
|
|
|
LabelSwVersion,
|
|
|
|
LabelUniqueID,
|
|
|
|
LabelStateButtonEvent,
|
|
|
|
LabelStateDaylight,
|
|
|
|
LabelStateLastUpdated,
|
|
|
|
LabelStateTemperature,
|
|
|
|
LabelConfigBattery,
|
|
|
|
LabelConfigOn,
|
|
|
|
LabelConfigReachable,
|
|
|
|
},
|
2020-12-28 08:49:18 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
metrics = append(metrics, &metric.Metric{
|
2020-12-28 17:29:44 +01:00
|
|
|
HueType: TypeSensor,
|
|
|
|
FqName: "hue_sensor_temperature",
|
|
|
|
Help: "temperature level celsius degree",
|
|
|
|
Labels: []string{
|
|
|
|
LabelName,
|
|
|
|
},
|
|
|
|
ResultKey: LabelStateTemperature,
|
2020-12-28 08:49:18 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
metrics = append(metrics, &metric.Metric{
|
2020-12-28 17:29:44 +01:00
|
|
|
HueType: TypeSensor,
|
|
|
|
FqName: "hue_sensor_lightlevel",
|
|
|
|
Help: "light level",
|
|
|
|
Labels: []string{
|
|
|
|
LabelName,
|
|
|
|
},
|
|
|
|
ResultKey: LabelStateLightLevel,
|
2020-12-28 08:49:18 +01:00
|
|
|
})
|
2020-12-22 18:24:23 +01:00
|
|
|
|
|
|
|
return metrics
|
|
|
|
}
|
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
// CollectAll available hue metrics
|
|
|
|
func CollectAll(url string, username string, fileName string) {
|
|
|
|
|
|
|
|
bridge := hueAPI.New(url, username)
|
|
|
|
|
|
|
|
jsonContent := []collectEntry{}
|
2020-12-22 18:24:23 +01:00
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
sensorData, err := collectSensors(bridge)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Sprintln(err)
|
|
|
|
return
|
|
|
|
}
|
2020-12-22 18:24:23 +01:00
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
lightData, err := collectLights(bridge)
|
2020-12-22 18:24:23 +01:00
|
|
|
if err != nil {
|
2020-12-28 17:29:44 +01:00
|
|
|
fmt.Sprintln(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, sensor := range sensorData {
|
|
|
|
jsonContent = append(jsonContent, collectEntry{
|
|
|
|
Type: "sensor",
|
|
|
|
Result: sensor,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, light := range lightData {
|
|
|
|
jsonContent = append(jsonContent, collectEntry{
|
|
|
|
Type: "light",
|
|
|
|
Result: light,
|
|
|
|
})
|
2020-12-22 18:24:23 +01:00
|
|
|
}
|
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
jsonString, err := json.MarshalIndent(jsonContent, "", "\t")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(string(jsonString))
|
|
|
|
if fileName != "" {
|
|
|
|
err = ioutil.WriteFile(fileName, jsonString, 0644)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Failed writing JSON file '%s': %s\n", fileName, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collect metrics
|
|
|
|
func (exporter *Exporter) Collect(metrics []*metric.Metric) (err error) {
|
|
|
|
|
|
|
|
bridge := hueAPI.New(exporter.BaseURL, exporter.Username)
|
|
|
|
|
2020-12-28 08:49:18 +01:00
|
|
|
sensorData, err := collectSensors(bridge)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-22 18:24:23 +01:00
|
|
|
|
2020-12-28 08:49:18 +01:00
|
|
|
lightData, err := collectLights(bridge)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-22 18:24:23 +01:00
|
|
|
|
2020-12-28 08:49:18 +01:00
|
|
|
for _, metric := range metrics {
|
2020-12-22 18:24:23 +01:00
|
|
|
switch metric.HueType {
|
|
|
|
case TypeLight:
|
2020-12-28 08:49:18 +01:00
|
|
|
metric.MetricResult = lightData
|
|
|
|
case TypeSensor:
|
|
|
|
metric.MetricResult = sensorData
|
2020-12-22 18:24:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
func collectSensors(bridge *hueAPI.Bridge) (sensorData []map[string]interface{}, err error) {
|
2020-12-27 14:58:21 +01:00
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
sensors, err := bridge.GetSensors()
|
2020-12-27 14:58:21 +01:00
|
|
|
if err != nil {
|
2020-12-28 08:49:18 +01:00
|
|
|
return nil, fmt.Errorf("[error GetAllSensors()] '%v'", err)
|
2020-12-27 14:58:21 +01:00
|
|
|
}
|
|
|
|
for _, sensor := range sensors {
|
|
|
|
result := make(map[string]interface{})
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelName] = sensor.Name
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelID] = sensor.ID
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelType] = sensor.Type
|
|
|
|
result[LabelModelID] = sensor.ModelID
|
|
|
|
result[LabelManufacturerName] = sensor.ManufacturerName
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelSwVersion] = sensor.SwVersion
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelUniqueID] = sensor.UniqueID
|
2020-12-28 17:29:44 +01:00
|
|
|
|
|
|
|
//State
|
|
|
|
for stateKey, stateValue := range sensor.State {
|
|
|
|
result["state_"+stateKey] = stateValue
|
|
|
|
}
|
|
|
|
|
|
|
|
//Config
|
|
|
|
for stateKey, stateValue := range sensor.Config {
|
|
|
|
result["config_"+stateKey] = stateValue
|
2020-12-27 14:58:21 +01:00
|
|
|
}
|
|
|
|
|
2020-12-28 08:49:18 +01:00
|
|
|
sensorData = append(sensorData, result)
|
2020-12-27 14:58:21 +01:00
|
|
|
}
|
2020-12-28 08:49:18 +01:00
|
|
|
return sensorData, nil
|
2020-12-27 14:58:21 +01:00
|
|
|
}
|
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
func collectLights(bridge *hueAPI.Bridge) (lightData []map[string]interface{}, err error) {
|
2020-12-22 18:24:23 +01:00
|
|
|
|
2020-12-28 17:29:44 +01:00
|
|
|
lights, err := bridge.GetLights()
|
2020-12-22 18:24:23 +01:00
|
|
|
if err != nil {
|
2020-12-28 08:49:18 +01:00
|
|
|
return nil, fmt.Errorf("[error GetAllLights()] '%v'", err)
|
2020-12-22 18:24:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, light := range lights {
|
|
|
|
|
|
|
|
result := make(map[string]interface{})
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelName] = light.Name
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelID] = light.ID
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelType] = light.Type
|
|
|
|
result[LabelModelID] = light.ModelID
|
|
|
|
result[LabelManufacturerName] = light.ManufacturerName
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelSwVersion] = light.SwVersion
|
|
|
|
result[LabelSwConfigID] = light.SwConfigID
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelUniqueID] = light.UniqueID
|
2020-12-28 17:29:44 +01:00
|
|
|
|
|
|
|
// State
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelStateOn] = light.State.On
|
|
|
|
result[LabelStateAlert] = light.State.Alert
|
|
|
|
result[LabelStateBri] = light.State.Bri
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelStateColorMode] = light.State.ColorMode
|
|
|
|
result[LabelStateCT] = light.State.Ct
|
2020-12-28 08:49:18 +01:00
|
|
|
result[LabelStateReachable] = light.State.Reachable
|
2020-12-28 17:29:44 +01:00
|
|
|
result[LabelStateSaturation] = light.State.Sat
|
2020-12-28 08:49:18 +01:00
|
|
|
|
|
|
|
lightData = append(lightData, result)
|
2020-12-22 18:24:23 +01:00
|
|
|
}
|
2020-12-28 08:49:18 +01:00
|
|
|
return lightData, nil
|
2020-12-22 18:24:23 +01:00
|
|
|
}
|