Skip to content

Commit ce41e90

Browse files
authored
DOCS-3695, DOCS-3401: Add to dependency, validate, and reconfigure info (#4089)
1 parent 18a10d9 commit ce41e90

1 file changed

Lines changed: 44 additions & 18 deletions

File tree

  • docs/operate/get-started/other-hardware

docs/operate/get-started/other-hardware/_index.md

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ Edit the generated files to add your logic:
155155
1. Open <file>/src/models/&lt;model-name&gt;.py</file> and add any necessary imports.
156156
1. **Edit the `validate_config` function** to do the following:
157157

158-
- Check that the user has configured required attributes
159-
- Return any implicit dependencies
158+
- Check that the user has configured required attributes and return errors if they are missing.
159+
- Return a map of any implicit dependencies.
160160

161161
<details>
162162
<summary><strong>Explicit versus implicit dependencies</strong></summary>
@@ -177,9 +177,12 @@ Edit the generated files to add your logic:
177177

178178
</details><br>
179179

180-
1. **Edit the `reconfigure` function** to do the following:
180+
1. **Edit the `reconfigure` function**, which gets called when the user changes the configuration.
181+
This function should do the following:
181182

182-
- Assign any default values as necessary to any optional attributes if the user hasn't configured them.<br><br>
183+
- If you assigned any configuration attributes to global variables, get the values from the latest `config` object and update the values of the global variables.
184+
- Assign default values as necessary to any optional attributes if the user hasn't configured them.
185+
- If your module has dependencies, get the dependencies from the `dependencies` map and cast each resource according to which API it implements, as in [this <file>ackermann.py</file> example](https://github.com/mcvella/viam-ackermann-base/blob/main/src/ackermann.py).
183186

184187
<ol><li style="counter-reset: item 3"><strong>Edit the methods you want to implement</strong>:
185188

@@ -370,8 +373,8 @@ LOGGER.critical("critical info")
370373

371374
1. **Edit the `Validate` function** to do the following:
372375

373-
- Check that the user has configured required attributes
374-
- Return any implicit dependencies
376+
- Check that the user has configured required attributes and return errors if they are missing.
377+
- Return any implicit dependencies.
375378

376379
<details>
377380
<summary><strong>Explicit versus implicit dependencies</strong></summary>
@@ -392,9 +395,21 @@ LOGGER.critical("critical info")
392395

393396
</details><br>
394397

395-
1. **Edit the `Reconfigure` function** to do the following:
398+
1. **(Optional) Create and edit a `Reconfigure` function**:
396399

397-
- Assign any default values as necessary to any optional attributes if the user hasn't configured them.<br><br>
400+
In most cases, you can omit this function and leave `resource.AlwaysRebuild` in the `Config` struct.
401+
This will cause `viam-server` to fully rebuild the resource each time the user changes the configuration.
402+
403+
If you need to maintain the state of the resource, for example if you are implementing a board and need to keep the software PWM loops running, you should implement this function so that `viam-server` updates the configuration without rebuilding the resource from scratch.
404+
In this case, your `Reconfigure` function should do the following:
405+
406+
- If you assigned any configuration attributes to global variables, get the values from the latest `config` object and update the values of the global variables.
407+
- Assign default values as necessary to any optional attributes if the user hasn't configured them.<br><br>
408+
409+
1. **Edit the constructor** to do the following:
410+
411+
- If you didn't create a `Reconfigure` function, use the constructor to assign default values as necessary to any optional attributes if the user hasn't configured them.
412+
- If you created a `Reconfigure` function, make your constructor call `Reconfigure`.<br><br>
398413

399414
<ol><li style="counter-reset: item 4"><strong>Edit the methods you want to implement</strong>:
400415

@@ -404,6 +419,7 @@ You can find details about the return types at [go.viam.com/rdk/components](http
404419

405420
{{< expand "Example code for a camera module" >}}
406421
This example from [Hello World module](/operate/get-started/other-hardware/hello-world-module/) implements only one method of the camera API by returning a static image.
422+
It demonstrates a required configuration attribute (`image_path`) and an optional configuration attribute (`example_value`).
407423

408424
```go {class="line-numbers linkable-line-numbers"}
409425
package hello_world
@@ -424,7 +440,6 @@ import (
424440
var (
425441
HelloCamera = resource.NewModel("jessamy", "hello-world", "hello-camera")
426442
errUnimplemented = errors.New("unimplemented")
427-
imagePath = ""
428443
)
429444

430445
func init() {
@@ -436,8 +451,8 @@ func init() {
436451
}
437452

438453
type Config struct {
439-
resource.AlwaysRebuild // Resource rebuilds instead of reconfiguring
440-
ImagePath string `json:"image_path"`
454+
ImagePath string `json:"image_path"`
455+
ExampleValue string `json:"example_value"`
441456
}
442457

443458
func (cfg *Config) Validate(path string) ([]string, error) {
@@ -448,16 +463,22 @@ func (cfg *Config) Validate(path string) ([]string, error) {
448463
if reflect.TypeOf(cfg.ImagePath).Kind() != reflect.String {
449464
return nil, errors.New("image_path must be a string.")
450465
}
451-
imagePath = cfg.ImagePath
466+
if cfg.ExampleValue != "" && reflect.TypeOf(cfg.ExampleValue).Kind() != reflect.String {
467+
return nil, errors.New("example_value must be a string.")
468+
}
452469
return deps, nil
453470
}
454471

455472
type helloWorldHelloCamera struct {
473+
resource.AlwaysRebuild // Resource rebuilds instead of reconfiguring
474+
456475
name resource.Name
457476

458477
logger logging.Logger
459478
cfg *Config
460479

480+
exampleValue string
481+
461482
cancelCtx context.Context
462483
cancelFunc func()
463484
}
@@ -476,25 +497,30 @@ func newHelloWorldHelloCamera(ctx context.Context, deps resource.Dependencies, r
476497
cfg: conf,
477498
cancelCtx: cancelCtx,
478499
cancelFunc: cancelFunc,
500+
}
501+
502+
s.exampleValue = s.cfg.ExampleValue
503+
if s.exampleValue == "" {
504+
s.exampleValue = "default value"
505+
s.logger.Debug("setting default exampleValue: %s", s.exampleValue)
479506
}
480-
return s, nil
507+
508+
return s, nil
481509
}
482510

483511
func (s *helloWorldHelloCamera) Name() resource.Name {
484512
return s.name
485513
}
486514

487-
func (s *helloWorldHelloCamera) Reconfigure(ctx context.Context, deps resource.Dependencies, conf resource.Config) error {
488-
return errUnimplemented
489-
}
490-
491515
func (s *helloWorldHelloCamera) Image(ctx context.Context, mimeType string, extra map[string]interface{}) ([]byte, camera.ImageMetadata, error) {
516+
imagePath := s.cfg.ImagePath
492517
imgFile, err := os.Open(imagePath)
493518
if err != nil {
494519
return nil, camera.ImageMetadata{}, errors.New("Error opening image.")
495520
}
496521
defer imgFile.Close()
497-
imgByte, err := ioutil.ReadFile(imagePath)
522+
imgByte, err := os.ReadFile(imagePath)
523+
s.logger.Info("The s.exampleValue is: " + s.exampleValue)
498524
return imgByte, camera.ImageMetadata{}, nil
499525
}
500526

0 commit comments

Comments
 (0)