Skip to content

Avoid multivalue properties split #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 20, 2022

Conversation

pennam
Copy link
Collaborator

@pennam pennam commented Dec 17, 2021

Problem:
with the current logic of CBOR message creation is actually possible that a multivalue property is splitted in two consecutive messages. This would break any multivalue property widget in create dashboard because is expected that all the values of the same multivalue property are updated at the same time.

Proposed solution:
Adding CHECK_CBOR_MULTI macro is possible to throw a CborErrorTooManyItems error when the whole multivalue property does not fit into the CBOR message. As a consequence the CBOR message is discarded (not sended to the cloud) and all the properties included in the discarded message and markes as appended_but_not_sended are scheduled for re-send. Furthermore the encoded_properties_message_limit is updated in order to send the correct number of properties to avoid re-trigger the error. The excluded property will be then sended in the next message. The same logic applies when the error occurs closing the CBOR container.

First run:

prop_a
prop_b
prop_c
multi_prop_d.1
multi_pror_d.2 <- CborErrorTooManyItems

Second run:

prop_a
prop_b
prop_c

Third run:

multi_prop_d.1
multi_pror_d.2 
...

Other changes:
Commits eb41da8 and ab527a1 are addressing a different but in some way correlated issue. If the propety container has a number of high change rate properties in the first positions and this properties are filling the CBOR message buffer these high change rate properties are updated each
sendPropertiesToCloud call leaving out the other properties.

This can be easily reproduced creating a sketch with 18 float properties and a loop like the one below. atest_12 is never updated.

void loop() {
  ArduinoCloud.update();
 
      atest_0++;
      atest_1++;
      atest_2++;
      atest_3++;
      atest_4++;
      atest_5++;
      atest_6++;
      atest_7++;
      atest_8++;
      atest_9++;
      atest_A++;
      atest_B++;
      atest_C++;
      atest_D++;
      atest_E++;
      atest_F++;
      atest_10++;
      atest_11++;
      atest_12++;
      delay(500);
}

Lastly since i've added the appended_but_not_sended i've also included commit 14eb479 that does not change any behaviour of the library, but it makes a bit clear that we need to echo back the received properties to the cloud even if unchanged.

/cc @eclipse1985

@pennam pennam requested a review from aentinger December 17, 2021 08:16
@codecov-commenter
Copy link

codecov-commenter commented Dec 17, 2021

Codecov Report

Merging #293 (8105d69) into master (fda11b5) will decrease coverage by 0.50%.
The diff coverage is 91.24%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #293      +/-   ##
==========================================
- Coverage   95.40%   94.89%   -0.51%     
==========================================
  Files          26       27       +1     
  Lines        1022     1116      +94     
==========================================
+ Hits          975     1059      +84     
- Misses         47       57      +10     
Impacted Files Coverage Δ
src/property/Property.h 88.88% <ø> (ø)
src/cbor/CBOREncoder.cpp 89.00% <88.88%> (-6.24%) ⬇️
src/property/Property.cpp 88.60% <92.30%> (+0.68%) ⬆️
src/cbor/CBOREncoder.h 100.00% <100.00%> (ø)
src/property/PropertyContainer.cpp 89.09% <100.00%> (+0.20%) ⬆️
src/property/types/CloudColor.h 97.05% <100.00%> (ø)
src/property/types/CloudLocation.h 100.00% <100.00%> (ø)
src/property/types/CloudSchedule.h 96.03% <100.00%> (ø)
src/property/types/automation/CloudColoredLight.h 100.00% <100.00%> (ø)
src/property/types/automation/CloudDimmedLight.h 100.00% <100.00%> (ø)
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fda11b5...8105d69. Read the comment docs.

Copy link
Contributor

@aentinger aentinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my most important feedback it to try and redesign the encoding logic into a FSM with named states, so that it's very clear in which state you are at all times and also the transitioning paths between the states are clearly visible. For a sample FSM pattern see here. 🙇 As always it's up to you to act on my feedback, please see it as a recommendation, not a request.

for(; iter != property_container.end(); iter++)
{
Property * p = * iter;
bool maximum_number_of_properties_reached = (num_encoded_properties >= encoded_properties_message_limit) && (encoded_properties_message_limit != -1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool maximum_number_of_properties_reached = (num_encoded_properties >= encoded_properties_message_limit) && (encoded_properties_message_limit != -1);
bool const maximum_number_of_properties_reached = (num_encoded_properties >= encoded_properties_message_limit) && (encoded_properties_message_limit != -1);

Use const-correctness as much as possible 😉

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. eedffb3

{
Property * p = * iter;
bool maximum_number_of_properties_reached = (num_encoded_properties >= encoded_properties_message_limit) && (encoded_properties_message_limit != -1);
bool cbor_encoder_error = (error != CborNoError);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool cbor_encoder_error = (error != CborNoError);
bool const cbor_encoder_error = (error != CborNoError);

Same as above. Btw, I love it that you are "encoding" the meaning of a boolean operation in the name of the boolean variable. Makes the if statement below so much more easily readable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above also fo me.

if (CborNoError != error)
{
/* Trim the number of properties to be included in the next message to avoid error closing container */
encoded_properties_message_limit = num_encoded_properties - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change feels like it uses encoded_properties_message_limit as both counter AND status variable. Can you think of a way to change the PR to encoded_properties_message_limit only as a counter (and possibly rename it) and use a boolean variable to cover the cases CBOR_ENCODER_NO_PROPERTIES_LIMIT and -1. If num_encoded_properties - 1 is also a valid state than this should be encoded as a FSM making the states and state transitions explicit. Right now states and state transitionings are hidden in the business logic and really hard to see.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the FSM here eedffb3 i've added a bool variable property_limit_active separate from the value encoded_property_limit.

And the two condition are handled in two separate states : TrimAppend and TrimClose

@pennam
Copy link
Collaborator Author

pennam commented Dec 17, 2021

I think my most important feedback it to try and redesign the encoding logic into a FSM with named states, so that it's very clear in which state you are at all times and also the transitioning paths between the states are clearly visible. For a sample FSM pattern see here. bow As always it's up to you to act on my feedback, please see it as a recommendation, not a request.

got it! i will take some time to think about it, but i agree that splitting the encoding process in basic operation would make the code more readable and the logic more explicit!. Thanks.

@aentinger
Copy link
Contributor

Great 👍 There's one thing that came to my mind additionally, which is that I'd suggest to capture the desired "output" within a unit test, i.e. you replicate your scenario where a multi-value property would be cut off, but isn't due to this change. Then you've got a much easier time refactoring this code, since you can run the tests after every change and be assured, that everything is still working as it should 😉

@pennam pennam force-pushed the avoid_multi_split branch 3 times, most recently from 1856d57 to 8105d69 Compare December 22, 2021 11:36
@arduino-libraries arduino-libraries deleted a comment from github-actions bot Dec 22, 2021
@arduino-libraries arduino-libraries deleted a comment from github-actions bot Dec 22, 2021
@github-actions
Copy link

Memory usage change @ 8105d69

Board flash % RAM for global variables %
arduino:mbed:envie_m4 🔺 +512 - +576 +0.05 - +0.05 🔺 +8 - +8 0.0 - 0.0
arduino:mbed:envie_m7 🔺 +512 - +512 +0.07 - +0.07 🔺 +8 - +8 0.0 - 0.0
arduino:mbed_nano:nanorp2040connect 0 - 0 0.0 - 0.0 🔺 0 - +4 0.0 - 0.0
arduino:samd:mkr1000 🔺 +496 - +544 +0.19 - +0.21 🔺 +8 - +8 +0.02 - +0.02
arduino:samd:mkrgsm1400 🔺 +496 - +544 +0.19 - +0.21 🔺 +8 - +8 +0.02 - +0.02
arduino:samd:mkrnb1500 🔺 +496 - +536 +0.19 - +0.2 🔺 +8 - +8 +0.02 - +0.02
arduino:samd:mkrwan1300 🔺 +496 - +536 +0.19 - +0.2 🔺 0 - +8 0.0 - +0.02
arduino:samd:mkrwifi1010 🔺 0 - +552 0.0 - +0.21 🔺 0 - +8 0.0 - +0.02
arduino:samd:nano_33_iot 🔺 0 - +552 0.0 - +0.21 🔺 0 - +8 0.0 - +0.02
esp32:esp32:esp32 🔺 +692 - +756 +0.05 - +0.06 🔺 0 - +8 0.0 - 0.0
esp8266:esp8266:huzzah 🔺 +656 - +704 +0.06 - +0.07 0 - 0 0.0 - 0.0
Click for full report table
Board examples/ArduinoIoTCloud-Advanced
flash
% examples/ArduinoIoTCloud-Advanced
RAM for global variables
% examples/ArduinoIoTCloud-Basic
flash
% examples/ArduinoIoTCloud-Basic
RAM for global variables
% examples/utility/ArduinoIoTCloud_Travis_CI
flash
% examples/utility/ArduinoIoTCloud_Travis_CI
RAM for global variables
% examples/utility/Provisioning
flash
% examples/utility/Provisioning
RAM for global variables
% examples/utility/SelfProvisioning
flash
% examples/utility/SelfProvisioning
RAM for global variables
%
arduino:mbed:envie_m4 576 0.05 8 0.0 512 0.05 8 0.0 512 0.05 8 0.0 512 0.05 8 0.0
arduino:mbed:envie_m7 512 0.07 8 0.0 512 0.07 8 0.0 512 0.07 8 0.0 512 0.07 8 0.0
arduino:mbed_nano:nanorp2040connect 0 0.0 4 0.0 0 0.0 4 0.0 0 0.0 4 0.0 0 0.0 4 0.0 0 0.0 0 0.0
arduino:samd:mkr1000 544 0.21 8 0.02 496 0.19 8 0.02 496 0.19 8 0.02 496 0.19 8 0.02
arduino:samd:mkrgsm1400 544 0.21 8 0.02 496 0.19 8 0.02 504 0.19 8 0.02 496 0.19 8 0.02
arduino:samd:mkrnb1500 536 0.2 8 0.02 496 0.19 8 0.02 496 0.19 8 0.02 496 0.19 8 0.02
arduino:samd:mkrwan1300 536 0.2 0 0.0 496 0.19 8 0.02 496 0.19 8 0.02
arduino:samd:mkrwifi1010 552 0.21 0 0.0 504 0.19 8 0.02 504 0.19 8 0.02 496 0.19 8 0.02 0 0.0 0 0.0
arduino:samd:nano_33_iot 552 0.21 0 0.0 504 0.19 8 0.02 504 0.19 8 0.02 504 0.19 8 0.02 0 0.0 0 0.0
esp32:esp32:esp32 756 0.06 0 0.0 720 0.05 8 0.0 692 0.05 8 0.0
esp8266:esp8266:huzzah 704 0.07 0 0.0 656 0.06 0 0.0 656 0.06 0 0.0
Click for full report CSV
Board,examples/ArduinoIoTCloud-Advanced<br>flash,%,examples/ArduinoIoTCloud-Advanced<br>RAM for global variables,%,examples/ArduinoIoTCloud-Basic<br>flash,%,examples/ArduinoIoTCloud-Basic<br>RAM for global variables,%,examples/utility/ArduinoIoTCloud_Travis_CI<br>flash,%,examples/utility/ArduinoIoTCloud_Travis_CI<br>RAM for global variables,%,examples/utility/Provisioning<br>flash,%,examples/utility/Provisioning<br>RAM for global variables,%,examples/utility/SelfProvisioning<br>flash,%,examples/utility/SelfProvisioning<br>RAM for global variables,%
arduino:mbed:envie_m4,576,0.05,8,0.0,512,0.05,8,0.0,512,0.05,8,0.0,512,0.05,8,0.0
arduino:mbed:envie_m7,512,0.07,8,0.0,512,0.07,8,0.0,512,0.07,8,0.0,512,0.07,8,0.0
arduino:mbed_nano:nanorp2040connect,0,0.0,4,0.0,0,0.0,4,0.0,0,0.0,4,0.0,0,0.0,4,0.0,0,0.0,0,0.0
arduino:samd:mkr1000,544,0.21,8,0.02,496,0.19,8,0.02,496,0.19,8,0.02,496,0.19,8,0.02,,,,
arduino:samd:mkrgsm1400,544,0.21,8,0.02,496,0.19,8,0.02,504,0.19,8,0.02,496,0.19,8,0.02,,,,
arduino:samd:mkrnb1500,536,0.2,8,0.02,496,0.19,8,0.02,496,0.19,8,0.02,496,0.19,8,0.02,,,,
arduino:samd:mkrwan1300,536,0.2,0,0.0,496,0.19,8,0.02,496,0.19,8,0.02,,,,,,,,
arduino:samd:mkrwifi1010,552,0.21,0,0.0,504,0.19,8,0.02,504,0.19,8,0.02,496,0.19,8,0.02,0,0.0,0,0.0
arduino:samd:nano_33_iot,552,0.21,0,0.0,504,0.19,8,0.02,504,0.19,8,0.02,504,0.19,8,0.02,0,0.0,0,0.0
esp32:esp32:esp32,756,0.06,0,0.0,720,0.05,8,0.0,692,0.05,8,0.0,,,,,,,,
esp8266:esp8266:huzzah,704,0.07,0,0.0,656,0.06,0,0.0,656,0.06,0,0.0,,,,,,,,

@pennam
Copy link
Collaborator Author

pennam commented Dec 22, 2021

Great +1 There's one thing that came to my mind additionally, which is that I'd suggest to capture the desired "output" within a unit test, i.e. you replicate your scenario where a multi-value property would be cut off, but isn't due to this change. Then you've got a much easier time refactoring this code, since you can run the tests after every change and be assured, that everything is still working as it should wink

Added a test here c620ad1

@pennam
Copy link
Collaborator Author

pennam commented Jan 13, 2022

Hi @aentinger did you had a chance to look at this commit eedffb3

@pennam pennam requested a review from aentinger January 13, 2022 10:28
@per1234 per1234 added topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project labels Jan 15, 2022
@aentinger
Copy link
Contributor

Good Morning @pennam ☕ 👋
I did look at the commit you referenced above and also at the complete PR. I feel a bit guilty like I intentionally misled you with my feedback, because now I'm going to ask you to cut a bit back on the states within your state machine. Basically the only states that need to be distinct states are the ones that can fail during a single execution of CborEncoder::encode.

An example: Neither handle_InitPropertyEncoder() nor handle_OpenCBORContainer() can fail, consequently they could be grouped in one state(EncoderState::Prepare)/function handle_Prepare(), i.e.

void handle_Prepare()
{
  handle_InitPropertyEncoder(propertyEncoder);
  handle_OpenCBORContainer(propertyEncoder, data, size);
  /* ... */
}

Otherwise you are pretty much there.

@@ -149,8 +149,9 @@ void ArduinoIoTCloudLPWAN::sendPropertiesToCloud()
{
int bytes_encoded = 0;
uint8_t data[CBOR_LORA_MSG_MAX_SIZE];
static unsigned int last_checked_property_index = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now is where you save the state for the CBOREncoder::encode state machine. I'd suggest to rather store it as a protected (not private, because both ArduinoIoTCloudLPWAN and ArduinoIoTCloudTCP need to access it) member variable of class ArduinoIoTCloud. Otherwise you've just created a hidden state variable. In my experience, everything that controls state in a C++ class should be listed as a member in the class body.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now i got it! plese see 5576a60

@@ -1,5 +1,5 @@
name=ArduinoIoTCloud
version=1.3.1
version=1.4.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you bump the library version number in this PR? It's of course possible, but the/my ususal flow is to merge the PR, than make a dedicated "release" commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ups, this was due to a wrong rebase, 1.4.0 is already released

@@ -596,12 +596,14 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(PropertyContainer & proper

void ArduinoIoTCloudTCP::sendPropertiesToCloud()
{
sendPropertyContainerToCloud(_property_container);
static unsigned int last_checked_property_index = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is hidden state. Please consider moving it to the class body.

Copy link
Contributor

@aentinger aentinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are getting there, only cosmetic changes are left 😉

…f the whole property cannot be appended to the CBOR buffer. Doing so the complete CBOR message will be discarded.
…e property, do not advance the property index and mark discarded properties has appended but not sended.

Compute the exact number of properties that would fit the CBOR buffer and retry send next loop. When no error occurs restore property limit to NO_LIMIT and advance property index.
… properties to be appended by one and retry send
@pennam pennam force-pushed the avoid_multi_split branch from 8105d69 to 78b3158 Compare January 18, 2022 10:30
@pennam
Copy link
Collaborator Author

pennam commented Jan 18, 2022

An example: Neither handle_InitPropertyEncoder() nor handle_OpenCBORContainer() can fail, consequently they could be grouped in one state(EncoderState::Prepare)/function handle_Prepare(), i.e.

I did not group this two states because even if they cannot fail they are doing different things. InitPropertyEncoder is called only at the beginning of each property chunck and is resetting encoded_property_limit counter and property_limit_active flag. OpenCBORContainer is called after InitPropertyEncoder, but also after TrimAppend and TrimClose and in this case we don't want to reset the conter and the flag.

I've grouped FinishAppend and AdvancePropertyContainer instead. See 78b3158

@github-actions
Copy link

Memory usage change @ 78b3158

Board flash % RAM for global variables %
arduino:mbed:envie_m4 🔺 +512 - +576 +0.05 - +0.05 0 - 0 0.0 - 0.0
arduino:mbed:envie_m7 🔺 +512 - +576 +0.07 - +0.07 0 - 0 0.0 - 0.0
arduino:mbed_nano:nanorp2040connect 0 - 0 0.0 - 0.0 0 - 0 0.0 - 0.0
arduino:samd:mkr1000 🔺 +480 - +528 +0.18 - +0.2 0 - 0 0.0 - 0.0
arduino:samd:mkrgsm1400 🔺 +488 - +536 +0.19 - +0.2 0 - 0 0.0 - 0.0
arduino:samd:mkrnb1500 🔺 +480 - +528 +0.18 - +0.2 0 - 0 0.0 - 0.0
arduino:samd:mkrwan1300 🔺 +480 - +520 +0.18 - +0.2 🔺 0 - +8 0.0 - +0.02
arduino:samd:mkrwifi1010 🔺 0 - +536 0.0 - +0.2 🔺 0 - +8 0.0 - +0.02
arduino:samd:nano_33_iot 🔺 0 - +536 0.0 - +0.2 🔺 0 - +8 0.0 - +0.02
esp32:esp32:esp32 🔺 +640 - +704 +0.05 - +0.05 🔺 0 - +8 0.0 - 0.0
esp8266:esp8266:huzzah 🔺 +624 - +672 +0.06 - +0.06 0 - 0 0.0 - 0.0
Click for full report table
Board examples/ArduinoIoTCloud-Advanced
flash
% examples/ArduinoIoTCloud-Advanced
RAM for global variables
% examples/ArduinoIoTCloud-Basic
flash
% examples/ArduinoIoTCloud-Basic
RAM for global variables
% examples/utility/ArduinoIoTCloud_Travis_CI
flash
% examples/utility/ArduinoIoTCloud_Travis_CI
RAM for global variables
% examples/utility/Provisioning
flash
% examples/utility/Provisioning
RAM for global variables
% examples/utility/SelfProvisioning
flash
% examples/utility/SelfProvisioning
RAM for global variables
%
arduino:mbed:envie_m4 576 0.05 0 0.0 512 0.05 0 0.0 512 0.05 0 0.0 512 0.05 0 0.0
arduino:mbed:envie_m7 576 0.07 0 0.0 512 0.07 0 0.0 512 0.07 0 0.0 512 0.07 0 0.0
arduino:mbed_nano:nanorp2040connect 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0 0 0.0
arduino:samd:mkr1000 528 0.2 0 0.0 480 0.18 0 0.0 480 0.18 0 0.0 480 0.18 0 0.0
arduino:samd:mkrgsm1400 536 0.2 0 0.0 488 0.19 0 0.0 488 0.19 0 0.0 488 0.19 0 0.0
arduino:samd:mkrnb1500 528 0.2 0 0.0 480 0.18 0 0.0 480 0.18 0 0.0 480 0.18 0 0.0
arduino:samd:mkrwan1300 520 0.2 0 0.0 480 0.18 8 0.02 480 0.18 8 0.02
arduino:samd:mkrwifi1010 536 0.2 0 0.0 488 0.19 8 0.02 488 0.19 8 0.02 488 0.19 8 0.02 0 0.0 0 0.0
arduino:samd:nano_33_iot 536 0.2 0 0.0 488 0.19 8 0.02 488 0.19 8 0.02 488 0.19 8 0.02 0 0.0 0 0.0
esp32:esp32:esp32 704 0.05 0 0.0 668 0.05 8 0.0 640 0.05 8 0.0
esp8266:esp8266:huzzah 672 0.06 0 0.0 624 0.06 0 0.0 624 0.06 0 0.0
Click for full report CSV
Board,examples/ArduinoIoTCloud-Advanced<br>flash,%,examples/ArduinoIoTCloud-Advanced<br>RAM for global variables,%,examples/ArduinoIoTCloud-Basic<br>flash,%,examples/ArduinoIoTCloud-Basic<br>RAM for global variables,%,examples/utility/ArduinoIoTCloud_Travis_CI<br>flash,%,examples/utility/ArduinoIoTCloud_Travis_CI<br>RAM for global variables,%,examples/utility/Provisioning<br>flash,%,examples/utility/Provisioning<br>RAM for global variables,%,examples/utility/SelfProvisioning<br>flash,%,examples/utility/SelfProvisioning<br>RAM for global variables,%
arduino:mbed:envie_m4,576,0.05,0,0.0,512,0.05,0,0.0,512,0.05,0,0.0,512,0.05,0,0.0
arduino:mbed:envie_m7,576,0.07,0,0.0,512,0.07,0,0.0,512,0.07,0,0.0,512,0.07,0,0.0
arduino:mbed_nano:nanorp2040connect,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0,0,0.0
arduino:samd:mkr1000,528,0.2,0,0.0,480,0.18,0,0.0,480,0.18,0,0.0,480,0.18,0,0.0,,,,
arduino:samd:mkrgsm1400,536,0.2,0,0.0,488,0.19,0,0.0,488,0.19,0,0.0,488,0.19,0,0.0,,,,
arduino:samd:mkrnb1500,528,0.2,0,0.0,480,0.18,0,0.0,480,0.18,0,0.0,480,0.18,0,0.0,,,,
arduino:samd:mkrwan1300,520,0.2,0,0.0,480,0.18,8,0.02,480,0.18,8,0.02,,,,,,,,
arduino:samd:mkrwifi1010,536,0.2,0,0.0,488,0.19,8,0.02,488,0.19,8,0.02,488,0.19,8,0.02,0,0.0,0,0.0
arduino:samd:nano_33_iot,536,0.2,0,0.0,488,0.19,8,0.02,488,0.19,8,0.02,488,0.19,8,0.02,0,0.0,0,0.0
esp32:esp32:esp32,704,0.05,0,0.0,668,0.05,8,0.0,640,0.05,8,0.0,,,,,,,,
esp8266:esp8266:huzzah,672,0.06,0,0.0,624,0.06,0,0.0,624,0.06,0,0.0,,,,,,,,

@aentinger
Copy link
Contributor

Makes sense 👍 Thank you very much for acting on my feedback 🙇.

@pennam
Copy link
Collaborator Author

pennam commented Jan 20, 2022

Makes sense +1 Thank you very much for acting on my feedback bow.

Thanks for your help @aentinger 💪

@pennam pennam merged commit 40bfd31 into arduino-libraries:master Jan 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants