Netatmo Weather Station

Display information sent by Netatmo Weather Station

Image preview of Netatmo Weather Station plugin.

netatmo.5m.go

Edit
Open on GitHub
#!/usr/bin/env gorun

// <xbar.title>Netatmo Weather Station</xbar.title>
// <xbar.version>v0.1</xbar.version>
// <xbar.author>Shinji Tanaka</xbar.author>
// <xbar.author.github>stanaka</xbar.author.github>
// <xbar.desc>Display information sent by Netatmo Weather Station</xbar.desc>
// <xbar.dependencies>go, gorun</xbar.dependencies>
// <xbar.image>https://raw.githubusercontent.com/stanaka/netatmo-xbar-plugin/main/netatmo-xbar-plugin.png</xbar.image>
// <xbar.abouturl>https://github.com/stanaka/netatmo-xbar-plugin/</xbar.abouturl>

// Variables

// <xbar.var>string(VAR_CLIENT_ID="client_id"): client id.</xbar.var>
// <xbar.var>string(VAR_CLIENT_SECRET="secret"): client secret.</xbar.var>
// <xbar.var>string(VAR_REFRESH_TOKEN="token"): client secret.</xbar.var>
// <xbar.var>select(VAR_STYLE="normal"): Which style to use. [small, normal, big]</xbar.var>

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
)

type ResponseAccessToken struct {
	Scope        []string `json:"scope"`
	AccessToken  string   `json:"access_token"`
	RefreshToken string   `json:"refresh_token"`
	ExpiresIn    int      `json:"expires_in"`
}

func getAccessToken() string {

	clientId := os.Getenv("VAR_CLIENT_ID")
	clientSecret := os.Getenv("VAR_CLIENT_SECRET")
	refreshToken := os.Getenv("VAR_REFRESH_TOKEN")

	uri := "https://api.netatmo.com/oauth2/token"
	resp, err := http.PostForm(uri,
		url.Values{
			"grant_type":    {"refresh_token"},
			"client_id":     {clientId},
			"client_secret": {clientSecret},
			"refresh_token": {refreshToken},
		})
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	byteArray, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	// fmt.Println(string(byteArray))

	var response ResponseAccessToken
	if err := json.Unmarshal(byteArray, &response); err != nil {
		log.Fatal(err)
	}

	return response.AccessToken
}

type Data struct {
	Temperature   *float64 `json:"Temperature"`
	Co2           *float64 `json:"CO2"`
	Humidity      *float64 `json:"Humidity"`
	Noise         *float64 `json:"Noise"`
	Pressure      *float64 `json:"Pressure"`
	TempTrend     *string  `json:"temp_trend"`
	PressureTrend *string  `json:"pressure_trend"`
}

func (d Data) printOneline() string {
	var s string
	if d.Temperature != nil {
		s += fmt.Sprintf("%.1f°C ", *d.Temperature)
	}
	if d.Co2 != nil {
		s += fmt.Sprintf("%.0fppm ", *d.Co2)
	}
	if d.Humidity != nil {
		s += fmt.Sprintf("%.0f%% ", *d.Humidity)
	}
	return s
}

func (d Data) print() string {
	var s string
	if d.Temperature != nil {
		s += fmt.Sprintf("Temp: %.1f °C\n", *d.Temperature)
	}
	if d.Co2 != nil {
		s += fmt.Sprintf("CO2: %.0f ppm\n", *d.Co2)
	}
	if d.Humidity != nil {
		s += fmt.Sprintf("Humid: %.0f %%\n", *d.Humidity)
	}
	return s
}

type Module struct {
	Id            string `json:"_id"`
	ModuleName    string `json:"module_name"`
	DashboardData Data   `json:"dashboard_data"`
}

type Device struct {
	Id            string   `json:"_id"`
	ModuleName    string   `json:"module_name"`
	DashboardData Data     `json:"dashboard_data"`
	Modules       []Module `json:"modules"`
}

type Body struct {
	Devices []Device `json:"devices"`
}

type Response struct {
	Body Body `json:"body"`
}

func main() {
	accessToken := getAccessToken()

	url := "https://api.netatmo.com/api/getstationsdata?get_favorites=false"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer "+accessToken)
	req.Header.Set("accept", "application/json")

	client := new(http.Client)
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	byteArray, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	var response Response
	if err := json.Unmarshal(byteArray, &response); err != nil {
		log.Fatal(err)
	}

	if len(response.Body.Devices) == 0 {
		fmt.Println(string(byteArray))
		log.Fatal("no device found")
	}

	fmt.Println(response.Body.Devices[0].DashboardData.printOneline())
	fmt.Println("---")
	fmt.Printf("%s | color=#ff0000\n", response.Body.Devices[0].ModuleName)
	fmt.Print(response.Body.Devices[0].DashboardData.print())
	for _, m := range response.Body.Devices[0].Modules {
		fmt.Printf("%s | color=#ff0000\n", m.ModuleName)
		fmt.Print(m.DashboardData.print())
	}
}