PlatformIO instead of official Arduino IDE?



  • Personally, I just started using it and prefer it a lot over the official IDE. Since I seem to now have at least one convert now (and it has come up in other threads too lately) I figured well maybe better to make a separate thread.

    I did a search, and there are some discussions going all the way back to 2016 (at least) which surprised me a bit, because (personally) I did not hear about PlatformIO until much more recently it seems.

    The main guy behind PlatformIO, Ivan, even has an account here and replied to a lot of questions before which I thought was very cool!

    The official IDE had almost turned me off entirely to Arduino development at one point. Now I tried again recently, and started out this time with PlatformIO and it has made all the difference for me! Developing on Arduino seems fun again! And much more organized (apparently to me fun == organized, but remember, I'm descended from Germans! 😄 )!

    Discuss.



  • @TRS-80 totally agree. Since I installed platform io, I have never used Arduino IDE anymore.
    It is more strict to the C++ standards, you have to make function prototypes for example, but that was all I had to convert basically.
    It is much easier to use with different library or platform versions on one system, has git build in and also the inline error checking saves a lot of time.



  • @electrik said in PlatformIO instead of official Arduino IDE:

    much easier to use with different library or platform versions on one system

    Yes! This is what I meant by finally feeling organized!

    For those who haven't used PlatformIO, you just do $ pio project init --board pro16MHzatmega328 (for example) in whatever directory, and it sets up folder structure and everything. Then there is a platform.ini file where you can specify what libraries you want to use (even pin them to specific versions!) and they will be automatically downloaded and put into appropriate folders within the current project only. So very easy and clear to keep libraries separated between projects.

    Here is my platform.ini for recent project with MySensors and Dallas Temperature libraries:

    ; PlatformIO Project Configuration File
    ;
    ;   Build options: build flags, source filter
    ;   Upload options: custom upload port, speed and extra flags
    ;   Library options: dependencies, extra library storages
    ;   Advanced options: extra scripting
    ;
    ; Please visit documentation for the other options and examples
    ; https://docs.platformio.org/page/projectconf.html
    
    [platformio]
    default_envs = pro16MHzatmega328
    
    [env:pro16MHzatmega328]
    platform = atmelavr
    board = pro16MHzatmega328
    framework = arduino
    lib_deps =
      548  ; MySensors
      54   ; DallasTemperature
    

    You can specify Libraries either by their name or number. I do by number because it's more accurate IMO. But the results will be sorted by popularity, so for example if you searched for (or specifed in your platformio.ini file) "MySensors" you would still get lib number 548 anyway. It's all very slick and well thought out.



  • @electrik said in PlatformIO instead of official Arduino IDE:

    the inline error checking saves a lot of time

    I used the official IDE so little, and it was so long ago, that I did not even remember that it doesn't do this (I thought it did! but I don't remember). So thanks for reminder!



  • If we compare the Arduino IDE and PlatformIO, we have to acknowledge that we're dealing with two different target audiences here. As someone who has never written a single line of C code when I decided to get into programming and electronics almost two years ago, I really appreciated how simple and straight forward the Arduino IDE made it to program a microcontroller. Automatic prototype generation has already been mentioned, one-click compiling and uploading, library management through the GUI,... and in general, the IDE makes it rather difficult to accidentally damage something. It's so simple and yet, it allows you to write highly sophisticated programs even though it gets cumbersome quite fast. I think the folks over at Arduino seem to have acknowleged that by developing the Arduino Pro IDE, providing a classic / basic and advanced mode, which sure is a step in the right direction.

    PlatformIO is a whole different beast. A purely text-based configuration and (not always optional) CLI commands aren't things I'd recommend to a beginner. It's much easier to brick a MCU or cause other issues inadvertendly because it's more "bare bone".

    I could list a whole lot of features PIO brings to the party, but it's easy enough to look them up on the website. They're all fine and useful, but in my oppinion, the biggest advantage of PIO is the possibility to integrate it into virtually any IDE or code editor you're already familiar with. It's a huge convenience and efficiency boost if you can keep using all the keyboard shortcuts you're used to already, along with all the advanced features other IDEs provide. PIO requires more commitment to understand and make use of it, but once you know how it's done, there's no going back.

    In the end, I think it depends a lot on everyones individual needs and experience which environemt is preferential.

    It is more strict to the C++ standards, you have to make function prototypes for example, but that was all I had to convert basically.

    This is what annoyed me for a long time after I switched to PIO. Copying code over from a Arduino IDE sketch for troubleshooting or whatever often meant reorganizing a bunch of cross-referencing functions. Turns out, if you rename the default main.cpp file to main.ino, it supports automatic function declarations and will compile just fine!

    On that note, here's a quick tip to make a PlatformIO project compatible with the Arduino IDE: Rename the src folder to something meaningful like BlinkWithoutDelay and rename the main.cpp file to BlinkWithoutDelay.ino. This satisfies the Arduino IDE's convention, where the main file has the same name as the directory it is in. You then need to tell PIO where the code has been moved to inside platformio.ini:

    [platformio]
    src_dir = BlinkWithoutDelay
    

    Now you can share the project with both PIO and Arduino IDE users and nobody should need to make any adjustments to get it working.

    It should also be possible to write a little script that automatically (re-)builds a separate Arduino IDE directory with everything in the src folder and let PIO execute it via extra_scripts whenever you build the program. This way you'd always keep a version for both environments.



  • @BearWithBeard said in PlatformIO instead of official Arduino IDE?:

    It should also be possible to write a little script that automatically (re-)builds a separate Arduino IDE directory with everything in the src folder and let PIO execute it via extra_scripts whenever you build the program. This way you'd always keep a version for both environments.

    Not sure if anyone has a use for it, but in order to get a little practice in Python I went ahead and wrote such a script, so I'll drop it here. Who knows, might come in handy at some point. 🤷‍♂️

    import configparser
    import distutils.dir_util
    import distutils.log
    import os
    import platform
    import re
    import shutil
    
    Import("env")
    
    logCopiedFilesToConsole: bool = False
    optionMainFile: str = "custom_main_file"
    optionArduinoDirName: str = "custom_arduino_dir"
    defaultMainFile: str = "main.cpp"
    arduinoFileType: str = ".ino"
    
    # Read and parse platformio.ini
    config = configparser.ConfigParser()
    if not config.read(env.get("PROJECT_CONFIG")):
        print("Unable to read platformio.ini")
    
    # Get paths and vars from SCons
    projectDir: str = env.get("PROJECT_DIR")
    projectSrcDir: str = env.get("PROJECTSRC_DIR")
    envSection: str = "env:" + env.get("PIOENV")
    projectName: str = os.path.basename(projectDir)
    
    
    def sanitizeUserInput(input: str, isPathOrFile: bool = False) -> str:
        """ Sanitize user input strings. """
        input = input.strip("\"'")
    
        # Make sure the string doesn't violate file system rules
        if isPathOrFile:
            if platform.system() == "Windows":
                input = re.sub("[<>:/\\|?*]+|[.]$", "", input)
            else:  # Unix, macOS
                input = re.sub("[/]+", "", input)
    
        return input
    
    
    def getOption(env: str, option: str) -> str:
        """ Retrieve a user-specified value from an environment option. """
        value = ""
    
        try:
            value = config.get(env, option)
        except configparser.NoOptionError:
            value = None  # To differentiate it from empty string
        except configparser.NoSectionError:
            print("Unable to find environment section %s" % env)
    
        return value
    
    
    def getMainFile(defaultFile: str) -> str:
        """ Get the user-specified main file.
            If none is provided, default to defaultMainFile (main.cpp). """
        name = getOption(envSection, optionMainFile)
    
        if not name or name is None:
            name = defaultFile
    
        return sanitizeUserInput(name, True)
    
    
    def getArduinoDirName(defaultName: str) -> str:
        """ Get the user-specified name for the Arduino IDE directory.
            If none is provided, default to project name. """
        name = getOption(envSection, optionArduinoDirName)
    
        if name is None:
            print("Using project name %s for the Arduino IDE directory.\n"
                  "Specify %s in %s to provide a custom name. "
                  % (defaultName, optionArduinoDirName, envSection))
    
        if not name or name is None:
            name = defaultName
    
        return sanitizeUserInput(name, True)
    
    
    def copySourceDir(source: str, dest: str, logCopiedFiles: bool = False) -> None:
        """ Copy nox-existing or modified files and folders. """
        if logCopiedFiles:
            distutils.log.set_verbosity(distutils.log.DEBUG)
    
        distutils.dir_util.copy_tree(source, dest, update=1)
    
    
    def renameFile(source: str, dest: str) -> None:
        """ Rename a single file. """
        if not os.path.isfile(source):
            print("%s does not exist. Trying to rename fallback %s to %s" %
                  (os.path.basename(source), defaultMainFile, os.path.basename(dest)))
            source = os.path.join(arduinoDir, defaultMainFile)
    
        try:
            os.replace(source, dest)
        except OSError:
            print("Unable to rename %s to %s" %
                  (os.path.basename(source), os.path.basename(dest)))
    
    
    def getFilesInDir(directory: str) -> str:
        """ Get a list of strings of all files in a directory tree. """
        filelist = []
    
        for root, dirs, files in os.walk(directory):
            dir = root.replace(directory, '')
            for file in files:
                filelist.append(os.path.join(dir, file))
    
        return filelist
    
    
    def cleanupArduinoDir() -> None:
        """ Compare contents of source and Arduino directory trees.
            Remove all files and directories in the Arduino directory which are 
            not present in the source directory."""
        srcDirContents = getFilesInDir(projectSrcDir)
        arduinoDirContents = getFilesInDir(arduinoDir)
    
        filesToRemove = set(arduinoDirContents) - set(srcDirContents)
    
        # Remove all files which aren't in the source dir
        for file in filesToRemove:
            if not file == mainArduinoFile:
                os.remove(os.path.join(arduinoDir, file.lstrip("/\\")))
    
        # Remove all empty folders
        for root, dirs, files in os.walk(arduinoDir, topdown=False):
            for dir in dirs:
                try:
                    os.rmdir(os.path.join(root, dir))
                except OSError:
                    pass  # Dir not empty, we want to keep it
    
    
    arduinoDirName: str = getArduinoDirName(projectName)
    arduinoDir: str = os.path.join(projectDir, arduinoDirName)
    mainFile = getMainFile(defaultMainFile)
    mainArduinoFile: str = arduinoDirName + arduinoFileType
    
    copySourceDir(projectSrcDir, arduinoDir, logCopiedFilesToConsole)
    renameFile(os.path.join(arduinoDir, mainFile),
               os.path.join(arduinoDir, mainArduinoFile))
    cleanupArduinoDir()
    
    

    It creates a discrete directory for the Arduino IDE in the root of the PIO project and copies all files and folders inside the source directory over. It only copies files which have been modified or aren't yet in the Arduino IDE directory. The main code file will be renamed accordingly and the directory cleaned up afterwards.

    Since all required paths and variables are retrieved from PIOs construction environment, it still works for customized project structures, for example if src_dir has been moved. This also means that it doesn't matter where you put the script. Keep a copy of the script with every project or provide a single one globally - just make sure to provide a valid path to it with the extra_scripts option and PIO will execute it whenever you create a new build.

    Add the following line(s) to your platformio.ini:

    [env:yourenv]
    ...
    custom_main_file = start.c
    custom_arduino_dir = ArduinoProject
    extra_scripts = post:build_arduino_dir.py
    

    custom_main_file is optional and can be specified, if main.cpp is renamed to something else (here: start.c). This file will be renamed to the main .ino file.

    custom_arduino_dir is optional as well. You can provide a custom name for the new directory and the main .ino file. If none is provided, it defaults to the name of the PIO project directory.

    For example, path/MyProject/src/main.cpp will result in path/MyProject/MyProject/MyProject.ino per default. With "ArduinoProject" specified for custom_arduino_dir, it'll create path/MyProject/ArduinoProject/ArduinoProject.ino.

    Tested on Win 10 and Arch Linux.



  • @TRS-80
    "Arduino IDE" is hardly an glorified notepad, it is beyond useless, why can't it save your board config with your project FFS!!!.
    I'm using arduino plugin for atmel studio, since it's only way to use hardware debuggers, both AVR dragon and ATMEL ICE work great.



  • I also want to highlight one problem of the arduino IDE, and that is that it is very local to your machine. It makes hard to share your projects with others or even to migrate to a different machine of yours. This may not be a problem for casual editions, but as soon as you have build 5 or 10 things this starts to be a concern. People should be able to store their projects whenever they want and not be tied to specific paths/configs on a particular machine.


Log in to reply
 

Suggested Topics

0
Online

11.4k
Users

11.1k
Topics

112.7k
Posts