-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add ADC implementation & sensors (#40)
* chore: define Option type to know if value is set. * feat: Add ADC implementation Also add battery sensor that uses ADC. * fix formatting value missing args * initial power config Zigbee cluster * remove debug adc loop execution * add free calls for bufid in callbacks This should've been done before, but I was not sure if it was needed or not. * replace humidity with general water content cluster impl This would allow sharing the cluster for other water measurement clusters, as they have same attributes and behavior. * feat: Add ADC soil moisture sensor It is generic, and should be configured properly for each use & sensor, but implementation is shared.
- Loading branch information
Showing
34 changed files
with
1,037 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package base | ||
|
||
import ( | ||
"github.com/ffenix113/zigbee_home/cli/templates/extenders" | ||
"github.com/ffenix113/zigbee_home/cli/types/appconfig" | ||
"github.com/ffenix113/zigbee_home/cli/types/devicetree" | ||
"github.com/ffenix113/zigbee_home/cli/types/generator" | ||
"github.com/ffenix113/zigbee_home/cli/zcl/cluster" | ||
) | ||
|
||
type PowerConfiguration struct { | ||
*Base `yaml:",inline"` | ||
cluster.PowerConfiguration `yaml:",inline"` | ||
ADCPin devicetree.ADCPin `yaml:"adc_pin"` | ||
} | ||
|
||
func (*PowerConfiguration) String() string { | ||
return "PowerConfiguration" | ||
} | ||
|
||
func (*PowerConfiguration) Template() string { | ||
return "sensors/power_config" | ||
} | ||
|
||
func (o *PowerConfiguration) Clusters() cluster.Clusters { | ||
clusterConfig := o.PowerConfiguration | ||
clusterConfig.BatteryRatedVoltage /= 100 | ||
clusterConfig.BatteryVoltageMinThreshold /= 100 | ||
return []cluster.Cluster{ | ||
clusterConfig, | ||
} | ||
} | ||
|
||
func (*PowerConfiguration) AppConfig() []appconfig.ConfigValue { | ||
return []appconfig.ConfigValue{ | ||
appconfig.NewValue("CONFIG_ADC").Required(appconfig.Yes), | ||
} | ||
} | ||
|
||
func (o *PowerConfiguration) ApplyOverlay(overlay *devicetree.DeviceTree) error { | ||
dtPin := devicetree.NewButton(o.ADCPin.Pin) | ||
return dtPin.AttachSelf(overlay) | ||
} | ||
|
||
func (c *PowerConfiguration) Extenders() []generator.Extender { | ||
return []generator.Extender{ | ||
extenders.NewADC(c.ADCPin), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package base | ||
|
||
import ( | ||
"github.com/ffenix113/zigbee_home/cli/templates/extenders" | ||
"github.com/ffenix113/zigbee_home/cli/types/appconfig" | ||
"github.com/ffenix113/zigbee_home/cli/types/devicetree" | ||
"github.com/ffenix113/zigbee_home/cli/types/generator" | ||
"github.com/ffenix113/zigbee_home/cli/zcl/cluster" | ||
) | ||
|
||
type SoilMoistureADC struct { | ||
*Base `yaml:",inline"` | ||
MinMoistureMv uint16 `yaml:"min_moisture_mv"` | ||
MaxMoistureMv uint16 `yaml:"max_moisture_mv"` | ||
ADCPin devicetree.ADCPin `yaml:"adc_pin"` | ||
} | ||
|
||
func (*SoilMoistureADC) String() string { | ||
return "SoilMoistureADC" | ||
} | ||
|
||
func (*SoilMoistureADC) Template() string { | ||
return "sensors/soil_moisture_adc" | ||
} | ||
|
||
func (o *SoilMoistureADC) Clusters() cluster.Clusters { | ||
return []cluster.Cluster{ | ||
// Hardcoded, as we don't configure this values. | ||
cluster.NewSoilMoisture(0, 100), | ||
} | ||
} | ||
|
||
func (*SoilMoistureADC) AppConfig() []appconfig.ConfigValue { | ||
return []appconfig.ConfigValue{ | ||
appconfig.NewValue("CONFIG_ADC").Required(appconfig.Yes), | ||
} | ||
} | ||
|
||
func (o *SoilMoistureADC) ApplyOverlay(overlay *devicetree.DeviceTree) error { | ||
dtPin := devicetree.NewButton(o.ADCPin.Pin) | ||
return dtPin.AttachSelf(overlay) | ||
} | ||
|
||
func (c *SoilMoistureADC) Extenders() []generator.Extender { | ||
return []generator.Extender{ | ||
extenders.NewADC(c.ADCPin), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package extenders | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ffenix113/zigbee_home/cli/types/devicetree" | ||
"github.com/ffenix113/zigbee_home/cli/types/generator" | ||
) | ||
|
||
var _ generator.Extender = ADC{} | ||
var _ devicetree.Applier = ADC{} | ||
|
||
type ADC struct { | ||
generator.SimpleExtender | ||
|
||
Instances []devicetree.ADCPin | ||
} | ||
|
||
func NewADC(instances ...devicetree.ADCPin) generator.Extender { | ||
return ADC{ | ||
Instances: instances, | ||
} | ||
} | ||
|
||
func (l ADC) Template() string { | ||
return "peripherals/adc" | ||
} | ||
|
||
func (l ADC) WriteFiles() []generator.WriteFile { | ||
return []generator.WriteFile{ | ||
{ | ||
FileName: "adc.c", | ||
TemplateName: "adc.c", | ||
}, | ||
{ | ||
FileName: "adc.h", | ||
TemplateName: "adc.h", | ||
}, | ||
} | ||
} | ||
|
||
func (l ADC) Includes() []string { | ||
return []string{"zephyr/drivers/adc.h", "adc.h"} | ||
} | ||
|
||
func (l ADC) ApplyOverlay(dt *devicetree.DeviceTree) error { | ||
for _, instance := range l.Instances { | ||
if err := instance.AttachSelf(dt); err != nil { | ||
return fmt.Errorf("attach adc: %w", err) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include <stdint.h> | ||
#include <zephyr/drivers/adc.h> | ||
#include <zephyr/logging/log.h> | ||
|
||
LOG_MODULE_DECLARE(app, LOG_LEVEL_INF); | ||
|
||
int zigbee_home_read_adc_mv(const struct adc_dt_spec *spec, int32_t *valp) { | ||
int err; | ||
uint16_t buf; | ||
struct adc_sequence sequence = { | ||
.buffer = &buf, | ||
/* buffer size in bytes, not number of samples */ | ||
.buffer_size = sizeof(buf), | ||
}; | ||
|
||
(void)adc_sequence_init_dt(spec, &sequence); | ||
err = adc_read(spec->dev, &sequence); | ||
if (err < 0) { | ||
LOG_DBG("ADC %s@%d: Could not read (%d)\n", spec->dev->name, spec->channel_id, err); | ||
return err; | ||
} | ||
|
||
/* | ||
* If using differential mode, the 16 bit value | ||
* in the ADC sample buffer should be a signed 2's | ||
* complement value. | ||
*/ | ||
int32_t val_mv; | ||
if (spec->channel_cfg.differential) { | ||
val_mv = (int32_t)((int16_t)buf); | ||
} else { | ||
val_mv = (int32_t)buf; | ||
} | ||
|
||
LOG_DBG("ADC %s@%d raw value: %d", spec->dev->name, spec->channel_id, val_mv); | ||
err = adc_raw_to_millivolts_dt(spec, &val_mv); | ||
/* conversion to mV may not be supported, skip if not */ | ||
if (err < 0) { | ||
LOG_DBG(" (value in mV not available)"); | ||
return err; | ||
} | ||
|
||
LOG_DBG("ADC %s@%d mv value: %d", spec->dev->name, spec->channel_id, val_mv); | ||
|
||
*valp = val_mv; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#pragma once | ||
|
||
int zigbee_home_read_adc_mv(const struct adc_dt_spec *spec, int32_t *valp); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{{define "top_level"}} | ||
/* Data of ADC io-channels specified in devicetree. */ | ||
{{ range $i, $instance := .Extender.Instances }} | ||
static const struct adc_dt_spec adc_channel_{{$instance.Name}} = ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), {{$i}}); | ||
{{end}} | ||
{{end}} | ||
|
||
{{ define "loop"}} {{end}} | ||
|
||
|
||
{{ define "main"}} | ||
int err; | ||
{{ range .Extender.Instances }} | ||
err = adc_channel_setup_dt(&adc_channel_{{.Name}}); | ||
if (err < 0) { | ||
LOG_ERR("Could not setup channel '{{.Name}}' (%d)\n", err); | ||
return 0; | ||
} | ||
{{end}} | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
{{/* The templates are non-empty to force their usage. */}} | ||
{{ define "top_level" }} {{end}} | ||
{{ define "button_changed"}} {{/* button_status = has_button_changed(&{{.Sensor.Pin.Label}}, button_state, has_changed); */}}{{end}} | ||
{{ define "loop"}} | ||
|
||
int32_t batt_mv; | ||
int err = zigbee_home_read_adc_mv(&adc_channel_{{.Sensor.ADCPin.Name}}, &batt_mv); | ||
if (err) { | ||
LOG_ERR("Failed to read ADC value from ADC channel {{.Sensor.ADCPin.Name}}"); | ||
} | ||
{{ $cluster := (index .Sensor.Clusters 0) }} | ||
zb_uint8_t batt_mv_divided = batt_mv / 100; | ||
zb_zcl_status_t status = zb_zcl_set_attr_val({{.Endpoint}}, | ||
{{ $cluster.ID }}, | ||
ZB_ZCL_CLUSTER_SERVER_ROLE, | ||
ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, | ||
&(batt_mv_divided), | ||
ZB_FALSE); | ||
if (status) { | ||
LOG_ERR("Failed to set ZCL attribute for battery voltage sensor: %d", status); | ||
} | ||
{/* Endpoint subtracts 1 because seems that there is a bug | ||
in how endpoints are calculated for attribute structs. | ||
*/} | ||
zb_uint16_t rated_voltage = dev_ctx.{{$cluster.CVarName}}_{{sum .Endpoint -1}}_attrs.rated_voltage * 100; | ||
zb_uint16_t min_threshold = dev_ctx.{{$cluster.CVarName}}_{{sum .Endpoint -1}}_attrs.voltage_min_threshold * 100; | ||
|
||
zb_uint8_t percentage; | ||
if (batt_mv >= rated_voltage) { | ||
percentage = 200; | ||
} else if (batt_mv <= min_threshold) { | ||
percentage = 0; | ||
} else { | ||
percentage = (((batt_mv-min_threshold)*200) / (rated_voltage - min_threshold)); | ||
} | ||
|
||
// Have only 10% increments | ||
percentage = ((percentage + 10) / 20) * 20; | ||
|
||
LOG_DBG("ADC battery channel {{.Sensor.ADCPin.Name}}: rated: %d, threshold: %d, current mv: %d, percent(x2): %d", rated_voltage, min_threshold, batt_mv, percentage); | ||
status = zb_zcl_set_attr_val({{.Endpoint}}, | ||
{{ $cluster.ID }}, | ||
ZB_ZCL_CLUSTER_SERVER_ROLE, | ||
ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, | ||
&percentage, | ||
ZB_FALSE); | ||
if (status) { | ||
LOG_ERR("Failed to set ZCL attribute for battery percentage sensor: %d", status); | ||
} | ||
{{end}} | ||
{{ define "main"}} {{end}} |
Oops, something went wrong.