Can somebody have a look at my library

I hope, that this is the correct area to ask for a review of my project.
I have my very first library in the arduino ide library manager.
The library name is SequenceTiming.
Also the use of github is new for me.
Can somebody have a look at it and give me feedback.

  • Is the text at github good to understand (readme.md)
  • How do you find the .pdf in the docs folder? Is it to detailed?
  • What do you think that I use three .ino files?
  • Different files.
    • LICENSE
    • keywords.txt. I do not see a difference in Arduino IDE. Is this normal? Is my file not correct?
    • library.properties
    • .github/workflows .yml files

Should I make more examples which are between the simple ones and the complex?
Should I make an example where I use my library-class within a class? Or would this be to much?

Hi @Andreas1313.

Congratulations on reaching this milestone in your Arduino journey!

For the benefit of the other forum helpers, I'll share the link to the library's GitHub repository:

I would suggest changing this text:

to instead link directly to the referenced folder:

I would suggest using a Markdown file (as you did with the readme) instead of a PDF. This would have several benefits:

  • Makes the content searchable
  • Provides a clean diff of the revision history of the document
  • Makes it easy for others to contribute to the content

I think it could be written in a more clear manner, but I don't see a problem with the level of detail.

I think it adds unnecessary complexity to the relatively simple "10_selfRunningSimple" and "20_sequenceSimple" sketches.

It makes sense to split up large sketches into multiple files. It also makes sense to format your personal sketches according to your preferences, even in the case of small sketches. However, these example sketches are intended to provide a simple demonstration of the library and so I think it is better to avoid any unnecessary complexity.

The "30_boomBar" example has more code, so it might be more beneficial in this case.

This is incorrect. This file should contain the exact legal text of the license. A good source for license text is here:

In addition to correctly serving as a legal document, this will also allow GitHub and other tools to automatically detect the license type of your library. The license text source I linked above is the content used by GitHub's license detection system (the choosealicense.com website is managed by the GitHub company).

You can provide additional information about licensing (e.g., the offer for a commercial license) in the readme, or in a separate file if you prefer not to clutter up the readme with that content. But you should not place it in the LICENSE file as this will interfere with its ability to be read by machines.

Are you using Arduino IDE 2.x?

The keywords.txt file is only used by Arduino IDE 1.x. So it is expected that you won't see any effect from the file when using Arduino IDE 2.x.

It looks correct. Many library developers don't get the data format of the file correct, but you correctly used the single tab delimited format!

It looks pretty good. You might want to update the value of the url property:

GitHub automatically sets up a redirect when you rename your repository, so the outdated URL does still lead to the repository. However, it is best to avoid relying on such redirects, as it is possible they might stop working at some point in the future.

Very cool that you set up validation workflows!

The Arduino Lint workflow looks great.

This part of the other workflow is inefficient:

You are unnecessarily installing every boards platform in each of the matrix jobs, even though you have a separate job for each board.

You can avoid this by defining the name of the board's platform dependency in the matrix. Something like this:

--- a/.github/workflows/arduino-build.yml
+++ b/.github/workflows/arduino-build.yml
@@ -10,13 +10,19 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        fqbn:
-          - arduino:avr:uno
-          - arduino:avr:mega
-          - arduino:sam:arduino_due_x
-          - esp32:esp32:esp32
-          - rp2040:rp2040:arduino_nano_rp2040_connect
-          - arduino:mbed_rp2040:rpipico
+        board:
+          - fqbn: arduino:avr:uno
+            platform: arduino:avr
+          - fqbn: arduino:avr:mega
+            platform: arduino:avr
+          - fqbn: arduino:sam:arduino_due_x
+            platform: arduino:sam
+          - fqbn: esp32:esp32:esp32
+            platform: esp32:esp32
+          - fqbn: rp2040:rp2040:arduino_nano_rp2040_connect
+            platform: rp2040:rp2040
+          - fqbn: arduino:mbed_rp2040:rpipico
+            platform: arduino:mbed_rp2040

     steps:
       - uses: actions/checkout@v4
@@ -27,14 +33,11 @@ jobs:
       - name: Install cores
         run: |
           arduino-cli core update-index
-          arduino-cli core install arduino:avr
-          arduino-cli core install arduino:sam
-          arduino-cli core install esp32:esp32
-          arduino-cli core install arduino:mbed_rp2040
+          arduino-cli core install ${{ matrix.board.platform }}

       - name: Compile examples
         run: |
           for sketch in $(find examples -name "*.ino"); do
-            echo "Compiling $sketch for ${{ matrix.fqbn }}"
-            arduino-cli compile --fqbn ${{ matrix.fqbn }} --library ./src $sketch
+            echo "Compiling $sketch for ${{ matrix.board.fqbn }}"
+            arduino-cli compile --fqbn ${{ matrix.board.fqbn }} --library ./src $sketch

This is also inefficient:

Since you have multiple .ino files in each of the example sketches, you are compiling each of the sketches multiple times

You can see it happening in the logs here:

https://github.com/Andreas1313/SequenceTiming/actions/runs/17048466277/job/48330117261#step:5:8

Compiling examples/30_boomBar/SetupLoop.ino for arduino:avr:uno
Sketch uses 4746 bytes (14%) of program storage space. Maximum is 32256 bytes.
Global variables use 562 bytes (27%) of dynamic memory, leaving 1486 bytes for local variables. Maximum is 2048 bytes.

Used library Version Path                                               
src                  /home/runner/work/SequenceTiming/SequenceTiming/src

Used platform Version Path                                                       
arduino:avr   1.8.6   /home/runner/.arduino15/packages/arduino/hardware/avr/1.8.6
Compiling examples/30_boomBar/30_boomBar.ino for arduino:avr:uno
Sketch uses 4746 bytes (14%) of program storage space. Maximum is 32256 bytes.
Global variables use 562 bytes (27%) of dynamic memory, leaving 1486 bytes for local variables. Maximum is 2048 bytes.

Used library Version Path                                               
src                  /home/runner/work/SequenceTiming/SequenceTiming/src

Used platform Version Path                                                       
arduino:avr   1.8.6   /home/runner/.arduino15/packages/arduino/hardware/avr/1.8.6
Compiling examples/30_boomBar/Functions.ino for arduino:avr:uno
Sketch uses 4746 bytes (14%) of program storage space. Maximum is 32256 bytes.
Global variables use 562 bytes (27%) of dynamic memory, leaving 1486 bytes for local variables. Maximum is 2048 bytes.

Used library Version Path                                               
src                  /home/runner/work/SequenceTiming/SequenceTiming/src

Used platform Version Path                                                       
arduino:avr   1.8.6   /home/runner/.arduino15/packages/arduino/hardware/avr/1.8.6

Do you notice that the "30_boomBar" example was compiled three times?

My suggestion is to use the arduino/compile-sketches action in the workflow:

This takes care of this sort of thing for you, so that you don't need to implement it in the workflow. arduino/compile-sketches uses Arduino CLI under the hood, so the actual compilation results are exactly the same as your current approach using Arduino CLI directly.

If you want to publish your library also on PlatformIO you need a

library.json file which looks like

{
  "name": "I2C_LCD",
  "keywords": "HD44780, 20x4, 16x2, lcd",
  "description": "Arduino library for I2C_LCD.",
  "authors":
  [
    {
      "name": "your name",
      "email": "your email",
      "maintainer": true
    }
  ],
  "repository":
  {
    "type": "git",
    "url": "https://github.com/RobTillaart/I2C_LCD.git"
  },
  "version": "0.2.4",
  "license": "MIT",
  "frameworks": "*",
  "platforms": "*",
  "headers": "I2C_LCD.h"
}

Note the keywords are for searching and not related to keywords.txt

Optionally add a JSON checker to verify the library.json file.
See GitHub - limitusus/json-syntax-check: Simple JSON syntax checker

Thank you for your very fast, detailed and professional answer.

When my project is more professional, I will think about to publish it on PlatformIO.

@Andreas1313, are you familiar with the wokwi simulator?


A compelling demo in the form of a complete sketch running in the simulator would be a great sales tool.

TBH I've had a bit too much of one thing and not enough of another; my mind refuses when I try to see what your library is up to and what it might do for me!

I was poking around a bit nevertheless and saw this comment

because of millis() overrun.(approx 50 days):

Which shouldn't be a problem for intervals that are nowhere near 49.71 days. What's going on there?

a7

@alto777 : No I am not familiar with wokwi simulator. I will have a look.

To your question: because of millis() overrun.(approx 50 days): (Thank you for having a look so deep in my library)
Now I have:

  ... 
 //This is called as long as the step is active:
  if (_event == Event::eventIsActive){
    // Step is in time:
    if (_in_latestStartNextStep_ms[uint32_t(_actualStep)] != 0){ //if == 0, _in_latestStartNextStep_ms is not used
      if (millis() - _oldActiveStep_ms >= _in_latestStartNextStep_ms[uint32_t(_actualStep)]){
        _error_latestStartNextStepReached = true;
        _event = Event::doNothingBecauseOfError;
        return;
      }
    }// "else" allone is not enough, because of millis() overrun.(approx 50 days):
    if (_nextStep != _actualStep){
      if (millis() - _oldActiveStep_ms < _in_earliestStartNextStep_ms[uint32_t(_actualStep)]){
        _error_earliestStartNextStepNotElapsed = true;
        ...

You are right, this comment makes no sense anymore. I have included this two lines a little bit later:

        _event = Event::doNothingBecauseOfError;
        return;

Before, I still run the _event == Event::eventIsActive also when there was an error.
I will remove this comment.

@ptillisch: I performed all of your suggestions.
Can you please have a look again. Especially at the arduino-build.yml.
Many thanks in advance.

This doesn't work:

Your workflow only results in the compilation for arduino:avr:uno. The other FQBNs are simply being ignored. You should use a separate matrix job for each board, as you had before:


And you are still unnecessarily installing all the boards platforms:

Now that you are using the arduino/compile-sketches action in your workflow, you can actually just omit the platforms input completely if you like:

https://github.com/arduino/compile-sketches#platforms

Default : The board's dependency will be automatically determined from the fqbn input and the latest version of that platform will be installed via Boards Manager.

You only need to specify platform dependencies in cases where more information is needed than what the action can automatically derive from the FQBN. For example, in the case where you are using a board from a 3rd party platform which requires providing an "additional Boards Manager URL" (as would be the case if you still wanted to compile for rp2040:rp2040:arduino_nano_rp2040_connect).

@ptillisch: Can you please have a look once again on my arduino-build.yml.
It was very hard for me to generate it. If you are not happy with it, can you please give me an example project, where it is done correct.

It looks pretty good!

The workflow seems to work fine as is, but this part is incorrect:

The correct code:

sketch-paths: |
  - examples

Reference: GitHub - arduino/compile-sketches: GitHub Actions action that checks whether Arduino sketches compile and produces a report of data from the compilations

In this use case, you can omit the sketch-paths input entirely as the default value is "- examples"

This is done in every official library, so you can look at any repository under the official arduino-libraries GitHub organization:

Here is a specific example in the official "Servo" library:

Note this approach, where the entire platforms input document is defined in the matrix, rather than only the platform ID as you have done in your workflow:

That approach is actually not necessary in the Servo workflow, but it is useful in the case where you have a board with a platform dependency that can not be described by an ID alone. An example of this is the esp8266:esp8266, for which a URL must be provided in addition to the ID.

I see you considered a different approach to that:

It should be possible to do it that way as well if you prefer.

@ptillisch. Thank you very much again for your professional answer. I have already written some tests for the functions of my library. But I want to improve them.
When I have more questions regarding .yml or project properties, I will come back to you.

@alto777: Have you ever worked with step sequencers (finite-state machines) 1) ? Step sequencers are suitable for many different applications where you want to complete one task after another. With my library, you can use different timing types in the step sequencer.

I plan to add simple example sketches for:

  • in_earliestStartNextStep_ms[] - get_error_earliestStartNextStepNotElapsed()
  • in_latestStartNextStep_ms[] - get_error_latestStartNextStepElapsed()
  • out_stepTime_ms[]

1) (infinite-state machines) correct: (finite-state machines) 01.09.2025

@alto777: Can you please have a look at my new library. Please find new examples 10_cylinder, 20_cylinder, 30_cylinder. I hope that you see there the advantage of my library.

You lost me at

a7

@alto777: I am very sorry, it was wrong writing. It must be finite-state-machine.