mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
9.0 KiB
Go
234 lines
9.0 KiB
Go
// Copyright 2026 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
package sen6x
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// VOCNOxAlgorithmTuningParameters represents parameters
|
|
// used to customize the VOC and NOx algorithm.
|
|
type VOCNOxAlgorithmTuningParameters struct {
|
|
// IndexOffset is the VOC or NOx index representing typical (average) conditions.
|
|
// Allowed values are in range 1..250. Device's default: 100 for VOC, 1 for NOx
|
|
IndexOffset int16
|
|
|
|
// LearningTimeOffsetHours is the time constant used to estimate the VOC/NOx
|
|
// algorithm offset from measurement history, in hours. Past events will be
|
|
// forgotten after about twice the learning time.
|
|
// Allowed values are in range 1..1000. Device's default: 12 hours
|
|
LearningTimeOffsetHours int16
|
|
|
|
// LearningTimeGainHours is the time constant used to estimate the VOC
|
|
// algorithm gain from measurement history, in hours. Past events will be
|
|
// forgotten after about twice the learning time.
|
|
// Allowed values are in range 1..1000. Device's default: 12 hours
|
|
//
|
|
// NOTE: This is only applicable to VOC. It has no impact for NOx. The datasheet
|
|
// says that this is included in the NOx parameters to keep it consistent with
|
|
// the VOC parameters. For NOx, it must always be set to 12.
|
|
LearningTimeGainHours int16
|
|
|
|
// GatingMaxDurationMinutes is the maximum duration of gating (freeze of
|
|
// estimator during high VOC/NOx index signal), in minutes. Zero disables
|
|
// gating. Allowed values are in range 0..3000. Device's default: 180 minutes
|
|
// for VOC, 720 minutes for NOx
|
|
GatingMaxDurationMinutes int16
|
|
|
|
// InitialStdDevEstimate is the initial VOC standard deviation estimate.
|
|
// A lower value boosts events during the initial learning period but may
|
|
// result in larger device-to-device variation. Allowed values are in range
|
|
// 10..5000. Device's default: 50
|
|
//
|
|
// NOTE: This is only applicable to VOC. It has no impact for NOx. The datasheet
|
|
// says that this is included in the NOx parameters to keep it consistent with
|
|
// the VOC parameters. For NOx, it must always be set to 50.
|
|
InitialStdDevEstimate int16
|
|
|
|
// GainFactor amplifies or attenuates the VOC/NOx index output.
|
|
// Allowed values are in range 1..1000. Device's default: 230
|
|
GainFactor int16
|
|
}
|
|
|
|
func (params VOCNOxAlgorithmTuningParameters) pack() []byte {
|
|
return packWordsWithCRC([]uint16{
|
|
uint16(params.IndexOffset),
|
|
uint16(params.LearningTimeOffsetHours),
|
|
uint16(params.LearningTimeGainHours),
|
|
uint16(params.GatingMaxDurationMinutes),
|
|
uint16(params.InitialStdDevEstimate),
|
|
uint16(params.GainFactor),
|
|
})
|
|
}
|
|
|
|
// GetVOCAlgorithmTuningParameters gets the parameters used to customize the
|
|
// VOC algorithm.
|
|
//
|
|
// For more information on the VOC index, see ["What is Sensirion's VOC Index?"].
|
|
// You may also consult "Sensirion's VOC and NOx Indices for Indoor Air Applications",
|
|
// available from Sensirion by request.
|
|
//
|
|
// ["What is Sensirion's VOC Index?"]: https://sensirion.com/media/documents/02232963/6294E043/Info_Note_VOC_Index.pdf
|
|
func (d *Dev) GetVOCAlgorithmTuningParameters() (*VOCNOxAlgorithmTuningParameters, error) {
|
|
if !d.model.hasVOCNOx() {
|
|
return nil, errors.New("sen6x: GetVOCAlgorithmTuningParameters requires a VOC-equipped model")
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
data, err := d.writeAndRead(cmdGetVOCAlgorithmTuningParamsSEN65SEN66SEN68SEN69C, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &VOCNOxAlgorithmTuningParameters{
|
|
IndexOffset: int16(binary.BigEndian.Uint16(data[0:2])),
|
|
LearningTimeOffsetHours: int16(binary.BigEndian.Uint16(data[2:4])),
|
|
LearningTimeGainHours: int16(binary.BigEndian.Uint16(data[4:6])),
|
|
GatingMaxDurationMinutes: int16(binary.BigEndian.Uint16(data[6:8])),
|
|
InitialStdDevEstimate: int16(binary.BigEndian.Uint16(data[8:10])),
|
|
GainFactor: int16(binary.BigEndian.Uint16(data[10:12])),
|
|
}, nil
|
|
}
|
|
|
|
// SetVOCAlgorithmTuningParameters sets the parameters used to customize the
|
|
// VOC algorithm.
|
|
//
|
|
// It has no effect if at least one parameter is outside the specified range.
|
|
//
|
|
// Note: This configuration is volatile, i.e. the parameters will be reverted
|
|
// to their default values after a device reset.
|
|
//
|
|
// For more information on the VOC index, see ["What is Sensirion's VOC Index?"].
|
|
// You may also consult "Sensirion's VOC and NOx Indices for Indoor Air Applications",
|
|
// available from Sensirion by request.
|
|
//
|
|
// ["What is Sensirion's VOC Index?"]: https://sensirion.com/media/documents/02232963/6294E043/Info_Note_VOC_Index.pdf
|
|
func (d *Dev) SetVOCAlgorithmTuningParameters(params VOCNOxAlgorithmTuningParameters) error {
|
|
if !d.model.hasVOCNOx() {
|
|
return errors.New("sen6x: SetVOCAlgorithmTuningParameters requires a VOC-equipped model")
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
return d.writeAndWait(cmdSetVOCAlgorithmTuningParamsSEN65SEN66SEN68SEN69C, params.pack())
|
|
}
|
|
|
|
// GetVOCAlgorithmState gets the current VOC algorithm state. This data can be
|
|
// used to restore the state with [Dev.SetVOCAlgorithmState] after a power cycle
|
|
// or device reset.
|
|
//
|
|
// This can be used either in measurement mode or in idle mode (which will then
|
|
// return the state at the time when the measurement was stopped). In measurement
|
|
// mode, the state can be read each measure interval to always have the latest
|
|
// state available.
|
|
func (d *Dev) GetVOCAlgorithmState() ([8]byte, error) {
|
|
if !d.model.hasVOCNOx() {
|
|
return [8]byte{}, errors.New("sen6x: GetVOCAlgorithmState requires a VOC-equipped model")
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
data, err := d.writeAndRead(cmdGetVOCAlgorithmStateSEN65SEN66SEN68SEN69C, nil)
|
|
if err != nil {
|
|
return [8]byte{}, err
|
|
}
|
|
|
|
if len(data) != 8 {
|
|
return [8]byte{}, fmt.Errorf("sen6x: expected VOC algorithm state to be 8 bytes, received %d", len(data))
|
|
}
|
|
|
|
return [8]byte(data), nil
|
|
}
|
|
|
|
// SetVOCAlgorithmState sets the VOC algorithm state previously received from
|
|
// [Dev.GetVOCAlgorithmState]. This command is only available in idle mode and
|
|
// the state will be applied when starting the next measurement. In measurement
|
|
// mode this command has no effect.
|
|
//
|
|
// Note: This configuration is volatile, i.e. the parameters will be reverted
|
|
// to their default values after a device reset.
|
|
func (d *Dev) SetVOCAlgorithmState(state [8]byte) error {
|
|
if !d.model.hasVOCNOx() {
|
|
return errors.New("sen6x: SetVOCAlgorithmState requires a VOC-equipped model")
|
|
}
|
|
|
|
packed, err := packBytesWithCRC(state[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
return d.writeAndWait(cmdSetVOCAlgorithmStateSEN65SEN66SEN68SEN69C, packed)
|
|
}
|
|
|
|
// GetNOxAlgorithmTuningParameters gets the parameters used to customize the
|
|
// NOx algorithm.
|
|
//
|
|
// For more information on the NOx index, see ["What is Sensirion's NOx Index?"].
|
|
// You may also consult "Sensirion's VOC and NOx Indices for Indoor Air Applications",
|
|
// available from Sensirion by request.
|
|
//
|
|
// ["What is Sensirion's NOx Index?"]: https://sensirion.com/media/documents/9F289B95/6294DFFC/Info_Note_NOx_Index.pdf
|
|
func (d *Dev) GetNOxAlgorithmTuningParameters() (*VOCNOxAlgorithmTuningParameters, error) {
|
|
if !d.model.hasVOCNOx() {
|
|
return nil, errors.New("sen6x: GetNOxAlgorithmTuningParameters requires a NOx-equipped model")
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
data, err := d.writeAndRead(cmdGetNOxAlgorithmTuningParamsSEN65SEN66SEN68SEN69C, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &VOCNOxAlgorithmTuningParameters{
|
|
IndexOffset: int16(binary.BigEndian.Uint16(data[0:2])),
|
|
LearningTimeOffsetHours: int16(binary.BigEndian.Uint16(data[2:4])),
|
|
LearningTimeGainHours: int16(binary.BigEndian.Uint16(data[4:6])),
|
|
GatingMaxDurationMinutes: int16(binary.BigEndian.Uint16(data[6:8])),
|
|
InitialStdDevEstimate: int16(binary.BigEndian.Uint16(data[8:10])),
|
|
GainFactor: int16(binary.BigEndian.Uint16(data[10:12])),
|
|
}, nil
|
|
}
|
|
|
|
// SetNOxAlgorithmTuningParameters sets the parameters used to customize the
|
|
// NOx algorithm.
|
|
//
|
|
// It has no effect if at least one parameter is outside the specified range.
|
|
//
|
|
// Note: This configuration is volatile, i.e. the parameters will be reverted
|
|
// to their default values after a device reset.
|
|
//
|
|
// For more information on the NOx index, see ["What is Sensirion's NOx Index?"].
|
|
// You may also consult "Sensirion's VOC and NOx Indices for Indoor Air Applications",
|
|
// available from Sensirion by request.
|
|
//
|
|
// ["What is Sensirion's NOx Index?"]: https://sensirion.com/media/documents/9F289B95/6294DFFC/Info_Note_NOx_Index.pdf
|
|
func (d *Dev) SetNOxAlgorithmTuningParameters(params VOCNOxAlgorithmTuningParameters) error {
|
|
if !d.model.hasVOCNOx() {
|
|
return errors.New("sen6x: SetNOxAlgorithmTuningParameters requires a NOx-equipped model")
|
|
}
|
|
|
|
// These two parameters only apply to VOC but are included in the NOx parameters
|
|
// for consistency. The datasheet specifies that these parameters must always
|
|
// have the values set here.
|
|
params.LearningTimeGainHours = 12
|
|
params.InitialStdDevEstimate = 50
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
return d.writeAndWait(cmdSetNOxAlgorithmTuningParamsSEN65SEN66SEN68SEN69C, params.pack())
|
|
}
|