Skip to content

Commit e48e04a

Browse files
[ESP32] Fix few attributes with fixed quality in DeviceInfoProvider (#32893)
* [ESP32] Fix few attributes with fixed quality in DeviceInfoProvider Fixed labels, supported locales, supported calendar types were being read from the nvs(flash) and during OTA its a hassle if one wants to upgrade these values. Added few APIs to set the data for these attributes in ESP32DeviceInfoProvider. * Restyled by clang-format * Restyled by prettier-markdown * fix the lint errors * Add back the original Device info provider which reads from the nvs Add StaticESP32DeviceInfoProvider along with APIs to set data Remove changes from example and add a guide along with usage --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent f084d65 commit e48e04a

7 files changed

+345
-131
lines changed

docs/guides/esp32/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ example on ESP32 series of SoCs
1818
- [Matter OTA](ota.md)
1919
- [Generating and Using ESP Secure Cert Partition](secure_cert_partition.md)
2020
- [BLE Settings](ble_settings.md)
21+
- [Providers](providers.md)

docs/guides/esp32/factory_data.md

+3-7
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,9 @@ Following data can be added to the manufacturing partition using
4444
- Serial Number
4545
- Unique identifier
4646

47-
- Device information
48-
- Fixed Labels
49-
- Supported locales
50-
- Supported calendar types
51-
- Supported modes
52-
- Note: As per spec at max size of label should be 64 and `\0` will be
53-
added at the end.
47+
- Supported modes
48+
- Note: As per spec at max size of label should be 64 and `\0` will be
49+
added at the end.
5450

5551
### Configuration Options
5652

docs/guides/esp32/providers.md

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
## Providers Implemented for ESP32 Platform
2+
3+
The ESP32 platform has implemented several providers that can be used with data
4+
stored in the factory or by setting fixed data.
5+
6+
Below are the providers that have been implemented:
7+
8+
- [Commissionable Data Provider](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/ESP32FactoryDataProvider.h#L47)
9+
This provider reads the discriminator and setup pincode related parameters
10+
from the factory partition.
11+
- [Device Attestation Credentials Provider](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/ESP32FactoryDataProvider.h#L56)
12+
This provider manages the attestation data.
13+
- [Device Instance Info Provider](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/ESP32FactoryDataProvider.h#L86)
14+
This provider reads basic device information from the factory partition.
15+
- [Device Info Provider](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/ESP32DeviceInfoProvider.h#L31)
16+
This provider provides fixed labels, supported calendar types, and supported
17+
locales from the factory partition.
18+
- [Supported Modes](https://github.com/project-chip/connectedhomeip/blob/master/examples/platform/esp32/mode-support/static-supported-modes-manager.h#L28)
19+
This provider offers the supported modes for the mode-select cluster.
20+
21+
More information can be found in the [factory data guide](factory_data.md).
22+
23+
### Device Info Provider
24+
25+
Currently, there are two implementations for this provider:
26+
27+
1. [Reads data stored in the factory partition](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/ESP32FactoryDataProvider.h#L56)
28+
_(This will be deprecated in the future)_
29+
2. [Provides APIs to set fixed data that gets read later](https://github.com/project-chip/connectedhomeip/blob/master/src/platform/ESP32/StaticESP32DeviceInfoProvider.h)
30+
31+
- New products should use the `StaticESP32DeviceInfoProvider`. Utilize the
32+
`Set...()` APIs to set the fixed data.
33+
- Existing products using the first implementation can continue to use it if
34+
they do not wish to change the data.
35+
- For products using the first implementation and wanting to change the fixed
36+
data via OTA, they should switch to the second implementation in the OTA
37+
image and use the `Set...()` APIs to set the fixed data.
38+
39+
#### Example:
40+
41+
```cpp
42+
#include <platform/ESP32/StaticESP32FactoryDataProvider.h>
43+
44+
DeviceLayer::StaticESP32DeviceInfoProvider deviceInfoProvider;
45+
46+
// Define array for Supported Calendar Types
47+
using namespace chip::app::Clusters::TimeFormatLocalization::CalendarTypeEnum;
48+
CalendarTypeEnum supportedCalendarTypes[] = {
49+
CalendarTypeEnum::kGregorian, CalendarTypeEnum::kCoptic,
50+
CalendarTypeEnum::kEthiopian, CalendarTypeEnum::kChinese,
51+
};
52+
53+
// Define array for Supported Locales
54+
const char* supportedLocales[] = {
55+
"en-US",
56+
"en-EU",
57+
};
58+
59+
// Define array for Fixed labels { EndpointId, Label, Value }
60+
struct StaticESP32DeviceInfoProvider::FixedLabelEntry fixedLabels[] = {
61+
{ 0, "Room", "Bedroom 2" },
62+
{ 0, "Orientation", "North" },
63+
{ 0, "Direction", "Up" },
64+
};
65+
66+
Span<CalendarTypeEnum> sSupportedCalendarTypes(supportedCalendarTypes);
67+
Span<const char*> sSupportedLocales(supportedLocales);
68+
Span<StaticESP32DeviceInfoProvider::FixedLabelEntry> sFixedLabels(fixedLabels);
69+
70+
{
71+
deviceInfoProvider.SetSupportedLocales(sSupportedLocales);
72+
deviceInfoProvider.SetSupportedCalendarTypes(sSupportedCalendarTypes);
73+
deviceInfoProvider.SetFixedLabels(sFixedLabels);
74+
DeviceLayer::SetDeviceInfoProvider(&deviceInfoProvider);
75+
}
76+
```

scripts/tools/generate_esp32_chip_factory_bin.py

-124
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@
1818

1919
import argparse
2020
import base64
21-
import enum
2221
import logging
2322
import os
2423
import sys
2524
from types import SimpleNamespace
2625

2726
import cryptography.x509
28-
from bitarray import bitarray
29-
from bitarray.util import ba2int
3027
from esp_secure_cert.tlv_format import generate_partition_ds, generate_partition_no_ds, tlv_priv_key_t, tlv_priv_key_type_t
3128

3229
CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('scripts', 'tools'))]
@@ -152,84 +149,16 @@
152149
'encoding': 'hex2bin',
153150
'value': None,
154151
},
155-
# DeviceInfoProvider
156-
'cal-types': {
157-
'type': 'data',
158-
'encoding': 'u32',
159-
'value': None,
160-
},
161-
'locale-sz': {
162-
'type': 'data',
163-
'encoding': 'u32',
164-
'value': None,
165-
},
166-
167-
# Other device info provider keys are dynamically generated
168-
# in the respective functions.
169152
}
170153

171154

172-
class CalendarTypes(enum.Enum):
173-
Buddhist = 0
174-
Chinese = 1
175-
Coptic = 2
176-
Ethiopian = 3
177-
Gregorian = 4
178-
Hebrew = 5
179-
Indian = 6
180-
Islamic = 7
181-
Japanese = 8
182-
Korean = 9
183-
Persian = 10
184-
Taiwanese = 11
185-
186-
187-
# Supported Calendar types is stored as a bit array in one uint32_t.
188-
def calendar_types_to_uint32(calendar_types):
189-
result = bitarray(32, endian='little')
190-
result.setall(0)
191-
for calendar_type in calendar_types:
192-
try:
193-
result[CalendarTypes[calendar_type].value] = 1
194-
except KeyError:
195-
logging.error('Unknown calendar type: %s', calendar_type)
196-
logging.error('Supported calendar types: %s', ', '.join(CalendarTypes.__members__))
197-
sys.exit(1)
198-
return ba2int(result)
199-
200-
201155
def ishex(s):
202156
try:
203157
_ = int(s, 16)
204158
return True
205159
except ValueError:
206160
return False
207161

208-
# get_fixed_label_dict() converts the list of strings to per endpoint dictionaries.
209-
# example input : ['0/orientation/up', '1/orientation/down', '2/orientation/down']
210-
# example output : {'0': [{'orientation': 'up'}], '1': [{'orientation': 'down'}], '2': [{'orientation': 'down'}]}
211-
212-
213-
def get_fixed_label_dict(fixed_labels):
214-
fl_dict = {}
215-
for fl in fixed_labels:
216-
_l = fl.split('/')
217-
218-
if len(_l) != 3:
219-
logging.error('Invalid fixed label: %s', fl)
220-
sys.exit(1)
221-
222-
if not (ishex(_l[0]) and (len(_l[1]) > 0 and len(_l[1]) < 16) and (len(_l[2]) > 0 and len(_l[2]) < 16)):
223-
logging.error('Invalid fixed label: %s', fl)
224-
sys.exit(1)
225-
226-
if _l[0] not in fl_dict.keys():
227-
fl_dict[_l[0]] = list()
228-
229-
fl_dict[_l[0]].append({_l[1]: _l[2]})
230-
231-
return fl_dict
232-
233162
# get_supported_modes_dict() converts the list of strings to per endpoint dictionaries.
234163
# example with semantic tags
235164
# input : ['0/label1/1/"1\0x8000, 2\0x8000" 1/label2/1/"1\0x8000, 2\0x8000"']
@@ -373,52 +302,6 @@ def populate_factory_data(args, spake2p_params):
373302
if args.hw_ver_str:
374303
FACTORY_DATA['hw-ver-str']['value'] = args.hw_ver_str
375304

376-
if args.calendar_types:
377-
FACTORY_DATA['cal-types']['value'] = calendar_types_to_uint32(args.calendar_types)
378-
379-
# Supported locale is stored as multiple entries, key format: "locale/<index>, example key: "locale/0"
380-
if args.locales:
381-
FACTORY_DATA['locale-sz']['value'] = len(args.locales)
382-
383-
for i in range(len(args.locales)):
384-
_locale = {
385-
'type': 'data',
386-
'encoding': 'string',
387-
'value': args.locales[i]
388-
}
389-
FACTORY_DATA.update({'locale/{:x}'.format(i): _locale})
390-
391-
# Each endpoint can contains the fixed lables
392-
# - fl-sz/<index> : number of fixed labels for the endpoint
393-
# - fl-k/<ep>/<index> : fixed label key for the endpoint and index
394-
# - fl-v/<ep>/<index> : fixed label value for the endpoint and index
395-
if args.fixed_labels:
396-
dict = get_fixed_label_dict(args.fixed_labels)
397-
for key in dict.keys():
398-
_sz = {
399-
'type': 'data',
400-
'encoding': 'u32',
401-
'value': len(dict[key])
402-
}
403-
FACTORY_DATA.update({'fl-sz/{:x}'.format(int(key)): _sz})
404-
405-
for i in range(len(dict[key])):
406-
entry = dict[key][i]
407-
408-
_label_key = {
409-
'type': 'data',
410-
'encoding': 'string',
411-
'value': list(entry.keys())[0]
412-
}
413-
_label_value = {
414-
'type': 'data',
415-
'encoding': 'string',
416-
'value': list(entry.values())[0]
417-
}
418-
419-
FACTORY_DATA.update({'fl-k/{:x}/{:x}'.format(int(key), i): _label_key})
420-
FACTORY_DATA.update({'fl-v/{:x}/{:x}'.format(int(key), i): _label_value})
421-
422305
# SupportedModes are stored as multiple entries
423306
# - sm-sz/<ep> : number of supported modes for the endpoint
424307
# - sm-label/<ep>/<index> : supported modes label key for the endpoint and index
@@ -584,13 +467,6 @@ def any_base_int(s): return int(s, 0)
584467
help=('128-bit unique identifier for generating rotating device identifier, '
585468
'provide 32-byte hex string, e.g. "1234567890abcdef1234567890abcdef"'))
586469

587-
# These will be used by DeviceInfoProvider
588-
parser.add_argument('--calendar-types', nargs='+',
589-
help=('List of supported calendar types.\nSupported Calendar Types: Buddhist, Chinese, Coptic, Ethiopian, '
590-
'Gregorian, Hebrew, Indian, Islamic, Japanese, Korean, Persian, Taiwanese'))
591-
parser.add_argument('--locales', nargs='+', help='List of supported locales, Language Tag as defined by BCP47, eg. en-US en-GB')
592-
parser.add_argument('--fixed-labels', nargs='+',
593-
help='List of fixed labels, eg: "0/orientation/up" "1/orientation/down" "2/orientation/down"')
594470
parser.add_argument('--supported-modes', type=str, nargs='+', required=False,
595471
help='List of supported modes, eg: mode1/label1/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode" mode2/label2/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode" mode3/label3/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode"')
596472

src/platform/ESP32/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ static_library("ESP32") {
185185
sources += [
186186
"ESP32DeviceInfoProvider.cpp",
187187
"ESP32DeviceInfoProvider.h",
188+
"StaticESP32DeviceInfoProvider.cpp",
189+
"StaticESP32DeviceInfoProvider.h",
188190
]
189191
}
190192

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
3+
* Copyright (c) 2024 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include <lib/support/CodeUtils.h>
18+
#include <platform/ESP32/StaticESP32DeviceInfoProvider.h>
19+
20+
namespace chip {
21+
namespace DeviceLayer {
22+
23+
StaticESP32DeviceInfoProvider & StaticESP32DeviceInfoProvider::GetDefaultInstance(void)
24+
{
25+
static StaticESP32DeviceInfoProvider sInstance;
26+
return sInstance;
27+
}
28+
29+
DeviceInfoProvider::FixedLabelIterator * StaticESP32DeviceInfoProvider::IterateFixedLabel(EndpointId endpoint)
30+
{
31+
return chip::Platform::New<StaticFixedLabelIteratorImpl>(endpoint, mFixedLabels);
32+
}
33+
34+
StaticESP32DeviceInfoProvider::StaticFixedLabelIteratorImpl::StaticFixedLabelIteratorImpl(EndpointId endpoint,
35+
const Span<FixedLabelEntry> & labels)
36+
{
37+
mEndpoint = endpoint;
38+
mLabels = labels;
39+
mIndex = 0;
40+
}
41+
42+
size_t StaticESP32DeviceInfoProvider::StaticFixedLabelIteratorImpl::Count()
43+
{
44+
size_t count = 0;
45+
for (size_t i = 0; i < mLabels.size(); i++)
46+
{
47+
const FixedLabelEntry & entry = mLabels.data()[i];
48+
49+
if (entry.endpointId == mEndpoint)
50+
{
51+
count++;
52+
}
53+
}
54+
return count;
55+
}
56+
57+
bool StaticESP32DeviceInfoProvider::StaticFixedLabelIteratorImpl::Next(FixedLabelType & output)
58+
{
59+
ChipLogDetail(DeviceLayer, "Get the fixed label with index:%u at endpoint:%d", static_cast<unsigned>(mIndex), mEndpoint);
60+
61+
while (mIndex < mLabels.size())
62+
{
63+
const FixedLabelEntry & entry = mLabels.data()[mIndex++];
64+
if (entry.endpointId == mEndpoint)
65+
{
66+
output.label = entry.label;
67+
output.value = entry.value;
68+
return true;
69+
}
70+
}
71+
72+
return false;
73+
}
74+
75+
DeviceInfoProvider::SupportedLocalesIterator * StaticESP32DeviceInfoProvider::IterateSupportedLocales()
76+
{
77+
return chip::Platform::New<StaticSupportedLocalesIteratorImpl>(mSupportedLocales);
78+
}
79+
80+
StaticESP32DeviceInfoProvider::StaticSupportedLocalesIteratorImpl::StaticSupportedLocalesIteratorImpl(
81+
const Span<CharSpan> & locales)
82+
{
83+
mLocales = locales;
84+
}
85+
86+
size_t StaticESP32DeviceInfoProvider::StaticSupportedLocalesIteratorImpl::Count()
87+
{
88+
return mLocales.empty() ? 0 : mLocales.size();
89+
}
90+
91+
bool StaticESP32DeviceInfoProvider::StaticSupportedLocalesIteratorImpl::Next(CharSpan & output)
92+
{
93+
VerifyOrReturnValue(mIndex < mLocales.size(), false);
94+
output = mLocales.data()[mIndex++];
95+
return true;
96+
}
97+
98+
DeviceInfoProvider::SupportedCalendarTypesIterator * StaticESP32DeviceInfoProvider::IterateSupportedCalendarTypes()
99+
{
100+
return chip::Platform::New<StaticSupportedCalendarTypesIteratorImpl>(mSupportedCalendarTypes);
101+
}
102+
103+
StaticESP32DeviceInfoProvider::StaticSupportedCalendarTypesIteratorImpl::StaticSupportedCalendarTypesIteratorImpl(
104+
const Span<CalendarType> & calendarTypes)
105+
{
106+
mCalendarTypes = calendarTypes;
107+
}
108+
109+
size_t StaticESP32DeviceInfoProvider::StaticSupportedCalendarTypesIteratorImpl::Count()
110+
{
111+
return mCalendarTypes.empty() ? 0 : mCalendarTypes.size();
112+
}
113+
114+
bool StaticESP32DeviceInfoProvider::StaticSupportedCalendarTypesIteratorImpl::Next(CalendarType & output)
115+
{
116+
VerifyOrReturnValue(mIndex < mCalendarTypes.size(), false);
117+
output = mCalendarTypes.data()[mIndex++];
118+
return true;
119+
}
120+
121+
} // namespace DeviceLayer
122+
} // namespace chip

0 commit comments

Comments
 (0)