youless

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2024 License: BSD-3-Clause Imports: 19 Imported by: 4

README

Client for YouLess energy monitor

Latest release Build status Go Report Card Documentation

Package youless contains a client which can read from the api of a YouLess device.

go get github.com/roeldev/youless-client
import "github.com/roeldev/youless-client"
API
Method Endpoint Description
GetDeviceInfo /d Get device information
GetMeterReading /e Get meter reading
GetPhaseReading /f Get phase reading
GetP1Telegram /V?p=# Get P1 telegram
GetLog /V Get report of Electricity utility
/W Get report of Gas utility
/K Get report of Water utility
/Z Get report of S0 utility
Utilities
Const Page Units
Electricity V Watt, kWh
S0 Z Watt, kWh
Gas W L, m3
Water K L, m3
Intervals
Const Interval Param LS110 history* LS120 history* Unit (electricity/s0) Unit (gas/water)
PerMin 1 minute h 1 hour (2x30) 10 hours (20x30) watt n/a
Per10Min 10 minutes w 1 day (3x48) 10 days (30x48) watt liter
PerHour 1 hour d 7 days (7x24) 70 days (70x24) watt liter
PerDay 1 day m 1 year (12x31) 1 year (12x31) kWh m3 (cubic meter)
  • = max. history (amount of pages x data entries)
Units
Const API equiv. Utilities
Watt Watt electricity, s0
KWh kWh electricity, s0
Liter L gas, water
CubicMeter m3 gas, water

Documentation

Additional detailed documentation is available at pkg.go.dev

Created with

License

Copyright © 2024 Roel Schut. All rights reserved.

This project is governed by a BSD-style license that can be found in the LICENSE file.

Documentation

Index

Constants

View Source
const (
	AttrDeviceMAC      = "youless.device.mac"
	AttrDeviceModel    = "youless.device.model"
	AttrDeviceFirmware = "youless.device.firmware"

	ErrReadPasswordFile errors.Msg = "failed to read password file"
	ErrPasswordRequired errors.Msg = "password required"
	ErrInvalidPassword  errors.Msg = "invalid password"
)
View Source
const (
	ErrInvalidBaseURL errors.Msg = "invalid base url"
	ErrInvalidConfig  errors.Msg = "invalid config"
)
View Source
const ErrApplyOption errors.Msg = "failed to apply option"
View Source
const LogTimeLayout = "2006-01-02T15:04:05"
View Source
const TimestampLayout = "0601021504"

TimestampLayout is the layout used for non-unix timestamps, its format is "YYMMDDHHmm".

View Source
const TracerName string = "youless-client"

Variables

This section is empty.

Functions

func ParseTimestamp added in v0.1.2

func ParseTimestamp(ts uint64) (time.Time, error)

ParseTimestamp parses a timestamp from a uint64 in layout TimestampLayout to a time.Time.

func ToTimestamp added in v0.1.2

func ToTimestamp(t time.Time) uint64

ToTimestamp converts a time.Time to an uint64 timestamp in layout TimestampLayout.

Types

type API

type API interface {
	GetDeviceInfo(ctx context.Context) (DeviceInfoResponse, error)
	GetMeterReading(ctx context.Context) (MeterReadingResponse, error)
	GetPhaseReading(ctx context.Context) (PhaseReadingResponse, error)
	GetLog(ctx context.Context, u Utility, i Interval, page uint) (LogResponse, error)
	GetP1Telegram(ctx context.Context) (P1TelegramResponse, error)
}

API is the interface containing all available api calls to the YouLess device.

type APIRequester

type APIRequester interface {
	API
	Requester
}

APIRequester implements both API and Requester interfaces.

func NewAPIRequester

func NewAPIRequester(r Requester) APIRequester

NewAPIRequester returns an APIRequester which uses Requester r to make requests to the YouLess device's api.

type Client

type Client struct {

	// Config contains the configuration for the Client.
	Config Config
	// contains filtered or unexported fields
}

Client is an APIRequester which connects with the Youless device and is able to groupRequest data from its api. Its zero value is ready to be used once Config.BaseURL is set. Client is not thread-safe. By default, it uses http.DefaultClient as http.Client, which can be replaced by calling NewClient with a WithHTTPClient Option.

func NewClient

func NewClient(conf Config, opts ...Option) (*Client, error)

NewClient creates a new Client with Config and applies any provided Option(s).

func (*Client) AuthCookie

func (c *Client) AuthCookie(ctx context.Context) (*http.Cookie, error)

AuthCookie returns the http.Cookie used for authentication. If the cookie is not yet fetched, it will try to fetch it by calling Authorize with the contents of Config.PasswordFile or Config.Password as password. When both fields are empty, it will return a nil http.Cookie, indicating the YouLess device does not need an auth cookie to access it's api.

func (*Client) Authorize

func (c *Client) Authorize(ctx context.Context, password string) (_ http.Cookie, err error)

Authorize sends a POST groupRequest to the YouLess device with the provided password. If the password is correct, it will return the received auth cookie from the device's api. Otherwise, it will return an ErrInvalidPassword error. Calling Authorize will replace any existing auth cookie with the new one.

func (*Client) GetDeviceInfo added in v0.2.0

func (api *Client) GetDeviceInfo(ctx context.Context) (DeviceInfoResponse, error)

func (*Client) GetLog

func (api *Client) GetLog(ctx context.Context, u Utility, i Interval, page uint) (LogResponse, error)

GetLog retrieves the log data for the given Utility and Interval at the provided page. Note: the page index starts at 1 and not 0.

func (*Client) GetMeterReading

func (api *Client) GetMeterReading(ctx context.Context) (MeterReadingResponse, error)

func (*Client) GetP1Telegram added in v0.2.0

func (api *Client) GetP1Telegram(ctx context.Context) (P1TelegramResponse, error)

func (*Client) GetPhaseReading

func (api *Client) GetPhaseReading(ctx context.Context) (PhaseReadingResponse, error)

func (*Client) Request

func (c *Client) Request(ctx context.Context, page string, out any) (err error)

func (*Client) With

func (c *Client) With(opts ...Option) error

With applies the provided Option(s) to the Client.

type Config

type Config struct {
	// BaseURL of the device.
	BaseURL string `json:"base_url" yaml:"baseUrl" default:"http://youless"`
	// Name of the device, is optional and used for logging/debugging.
	Name string `json:"name" yaml:"name" default:"YouLess"`
	// Timeout specifies a time limit for requests made by the http.Client used
	// by Client.
	Timeout time.Duration `json:"timeout" yaml:"timeout" default:"5s"`
	// Password used to connect with the device.
	Password string `json:"password" yaml:"password"`
	// PasswordFile contains the password used to connect with the device. When
	// both Password and PasswordFile are set, PasswordFile takes precedence.
	PasswordFile string `json:"password_file" yaml:"passwordFile"`
}

Config is the configuration for a Client. It can be unmarshalled from json, yaml, env or flag values.

func (Config) Validate

func (c Config) Validate() error

type DeviceInfoResponse added in v0.2.0

type DeviceInfoResponse struct {
	Model    string `json:"model"`
	Firmware string `json:"fw"`
	MAC      string `json:"mac"`
}

type ElectricityReading

type ElectricityReading struct {
	// Timestamp is a unix timestamp of the last meter reading.
	Timestamp int64 `json:"tm"`
	// ElectricityImport1 is the meter reading of total imported low tariff
	// electricity in kWh (Import 1).
	ElectricityImport1 float64 `json:"p1"`
	// ElectricityImport2 is the meter reading of total imported high tariff
	// electricity in kWh (Import 2).
	ElectricityImport2 float64 `json:"p2"`
	// ElectricityExport1 is the meter reading of total exported low tariff
	// electricity in kWh (Export 1).
	ElectricityExport1 float64 `json:"n1"`
	// ElectricityExport2 is the meter reading of total exported high tariff
	// electricity in kWh (Export 2).
	ElectricityExport2 float64 `json:"n2"`
	// NetElectricity is the total measured electricity which equals
	// (ElectricityImport1 + ElectricityImport2 - ElectricityExport1 - ElectricityExport2)
	// (Meterstand).
	NetElectricity float64 `json:"net"`
	// Power is the current imported (or negative for exported) electricity
	// power in Watt (Actueel vermogen).
	Power int64 `json:"pwr"`
}

func (ElectricityReading) Time

func (r ElectricityReading) Time() time.Time

type GasReading

type GasReading struct {
	// GasTimestamp is a timestamp in format "YYMMDDHHmm" of the last gas meter
	// reading.
	GasTimestamp uint64 `json:"gts"`
	// GasTotal is the meter reading of delivered gas (in m3) to client.
	GasTotal float64 `json:"gas"`
}

func (GasReading) Time

func (r GasReading) Time() time.Time

type Interval

type Interval uint32
const (
	PerMin   Interval = 60
	Per10min Interval = 600
	PerHour  Interval = 3600
	PerDay   Interval = 86400
)

func (Interval) Delta

func (i Interval) Delta() uint32

func (Interval) Duration

func (i Interval) Duration() time.Duration

func (Interval) Param

func (i Interval) Param() rune

func (Interval) String

func (i Interval) String() string

The String representation of Interval.

type LogResponse

type LogResponse struct {
	Unit      Unit     `json:"un"`
	Timestamp string   `json:"tm"`
	Interval  Interval `json:"dt"`
	RawValues []string `json:"val"`
}

func (LogResponse) Time

func (r LogResponse) Time() time.Time

func (LogResponse) TimeOfValue

func (r LogResponse) TimeOfValue(i uint) time.Time

func (LogResponse) TimedValues

func (r LogResponse) TimedValues() ([]TimedValue, error)

type Logger

type Logger interface {
	LogClientRequest(ctx context.Context, clientName, url string, shared bool)
	LogFetchAuthCookie(clientName string, cookie http.Cookie)
}

func DefaultLogger

func DefaultLogger() Logger

func NewLogger

func NewLogger(l *log.Logger) Logger

func NopLogger

func NopLogger() Logger

type MeterReadingResponse

type MeterReadingResponse struct {
	ElectricityReading
	S0Reading
	GasReading
	WaterReading
}

MeterReadingResponse is the response from the /e endpoint. It is a translation of a P1 telegram, with additional values, to JSON.

type Option

type Option func(c *Client) error

func WithDefaultLogger

func WithDefaultLogger() Option

func WithDefaultTracerProvider

func WithDefaultTracerProvider() Option

func WithHTTPClient

func WithHTTPClient(client http.Client) Option

WithHTTPClient sets the underlying http.Client for the client.

func WithLogger

func WithLogger(l Logger) Option

func WithTracer

func WithTracer(t trace.Tracer) Option

func WithTracerProvider

func WithTracerProvider(tp trace.TracerProvider) Option

WithTracerProvider sets a new tracer for the client from the specified tracer provider.

type P1TelegramResponse added in v0.2.0

type P1TelegramResponse struct {
	Data []byte
}

P1TelegramResponse contains a raw PI telegram response from the [API.GetP1Telegram] call.

type PhaseReading

type PhaseReading struct {
	// Current is the current imported electricity current in Ampere.
	Current float64
	// Power is the current imported electricity power in Watt.
	Power int64
	// Voltage is the current measured voltage.
	Voltage float64
}

PhaseReading contains the reading values of a single phase.

func (PhaseReading) InUse added in v0.2.0

func (r PhaseReading) InUse() bool

InUse indicates if the phase is in use or not.

type PhaseReadingResponse

type PhaseReadingResponse struct {
	// Tariff is the current tariff (Tarief).
	Tariff uint8 `json:"tr"`

	// Current1 is the current imported electricity current in Ampere on phase 1
	// (Stroom L1).
	Current1 float64 `json:"i1"`
	// Current2 is the current imported electricity current in Ampere on phase 2
	// (Stroom L2).
	Current2 float64 `json:"i2"`
	// Current3 is the current imported electricity current in Ampere on phase 3
	// (Stroom L3).
	Current3 float64 `json:"i3"`

	// Power1 is the current imported electricity power in Watt on phase 1
	// (Vermogen L1).
	Power1 int64 `json:"l1"`
	// Power2 is the current imported electricity power in Watt on phase 2
	// (Vermogen L2).
	Power2 int64 `json:"l2"`
	// Power3 is the current imported electricity power in Watt on phase 3
	// (Vermogen L3).
	Power3 int64 `json:"l3"`

	// Voltage1 is the current measured voltage on phase 1 (Spanning L1).
	Voltage1 float64 `json:"v1"`
	// Voltage2 is the current measured voltage on phase 2 (Spanning L2).
	Voltage2 float64 `json:"v2"`
	// Voltage3 is the current measured voltage on phase 3 (Spanning L3).
	Voltage3 float64 `json:"v3"`
}

https://community.home-assistant.io/t/youless-sensors-for-detailed-information-per-phase/433419 https://domoticx.com/p1-poort-slimme-meter-hardware/

func (PhaseReadingResponse) Phase1

Phase1 returns a PhaseReading of phase 1.

func (PhaseReadingResponse) Phase2

Phase2 returns a PhaseReading of phase 2.

func (PhaseReadingResponse) Phase3

Phase3 returns a PhaseReading of phase 3.

type Requester

type Requester interface {
	Request(ctx context.Context, path string, out any) error
}

Requester requests and handles calls to a YouLess device.

type S0Reading

type S0Reading struct {
	// S0Timestamp is a unix timestamp of the last S0 reading.
	S0Timestamp int64 `json:"ts0"`
	// S0Total is the total power in kWh measured by the S0 meter
	// (S0 meterstand).
	S0Total float64 `json:"cs0"`
	// S0 is the current electricity power measured in Watt from the S0 meter
	// (S0 vermogen).
	S0 int64 `json:"ps0"`
}

func (S0Reading) Time

func (r S0Reading) Time() time.Time

type TimedValue

type TimedValue struct {
	Time     time.Time
	Value    int64
	Inactive bool
}

func (TimedValue) String

func (tv TimedValue) String() string

type UnexpectedResponseError

type UnexpectedResponseError struct {
	StatusCode int
}

func (*UnexpectedResponseError) Error

func (e *UnexpectedResponseError) Error() string

type Unit

type Unit string
const (
	Watt       Unit = "Watt"
	KWh        Unit = "kWh"
	Liter      Unit = "L"
	CubicMeter Unit = "m3"

	ErrInvalidLogPage = "page cannot be <= 0; index starts at 1"
)

func (Unit) String

func (u Unit) String() string

type UnsupportedIntervalError

type UnsupportedIntervalError struct {
	Utility  Utility
	Interval Interval
}

func (UnsupportedIntervalError) Error

func (e UnsupportedIntervalError) Error() string

type Utility

type Utility string
const (
	Electricity Utility = "electricity"
	S0          Utility = "s0"
	Gas         Utility = "gas"
	Water       Utility = "water"
)

func (Utility) Endpoint

func (s Utility) Endpoint() string

Endpoint page of the utility's data on the YouLess' api.

func (Utility) String

func (s Utility) String() string

String returns the string representation of Utility.

type WaterReading

type WaterReading struct {
	// WaterTimestamp is a timestamp in format "YYMMDDHHmm" of the last water
	// meter reading.
	WaterTimestamp uint64 `json:"wts"`
	// WaterTotal is the meter reading of delivered water (in m3) to client.
	WaterTotal float64 `json:"wtr"`
}

func (WaterReading) Time

func (r WaterReading) Time() time.Time

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL