Setting up Arduino IDE in NixOS

4 minute read

I have recently installed some smart lights in my house in the form of some cheap Mirribela RGB LED bulbs that are powered by ESP32 chips so i can automate some of the lighting functions in my house as my family are shocking for leaving lights on all the time, These arnt the interesting part of this post though, Thanks to my darling Fiance hating all things technology (but yet being engaged to a DevSecOps Engineer and Tech enthusiast) because Hey google turn on x light is so inconviniant i have had a chance to flex my creative muscles and make an OTA esp-01 motion sensor that uses MQTT and a PIR sensor to trigger lights in Home Assistant.

This left me with a little conundrum, My Nix journey is still young so i have not quite figured out all the ins and outs of my development environments just yet which means i cant have both the SDK for the ESP32 and the SDK for the ESP8266 from espressif installed at the same time due to some nightmare dependancies and environment setup they share so i figured easy ill just whack on the Arduino IDE and do that, simple project simple tools turns out not so easy in Nix.

The Issue

While NixOS Packages the Arduino IDE and i did not test it with an AVR (I assume that works because it lives inside the Derivation but i could be wrong) to be able to program and ESP you need to install some packages through the board manager, Im not going to go into detail on how to acheive this there are litterally hudreds of thousands of tutorials on how to do this including from Espressif and Arduino.

So i completed that process as per normal and i just slapped a simple blink sketch together and tried to upload it to the esp-01 thats when this turned into a much bigger issue.

Failed to execute process '.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.0.4-gcc10.3-1757bed/bin/xtensa-lx106-elf-gcc'. Reason:
The file '.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.0.4-gcc10.3-1757bed/bin/xtensa-lx106-elf-gcc' does not exist or could not be executed.

Needless to say that did not go to plan and the error is not terribly helpfull, But from what i understand the error occours due to dynamic linking of the binarys when they were compiled and Nix’s nature makes those links break. Thankfully after many hours of googling i found a solution and in this case its nix-shell and buildFHSUserEnv to the rescue.

The Solution

So lets Save Many Many Hours of googling and lost sleep.

Because of the nature of NixOS and it being all set out into derivations some packages like Arduino in this case normal workflow does not work and there is not a Nix way to fill the gap in the workflow but it appears that issue is exactly why buildFHSUserEnv exists, I dont have a complete understanding of the process and the tool so i would suggest reading the docs for yourself as im also still working through them.

So im going to just jump to how i solved the problem so this post doesent end up a novel and dry boring nonsense.

#default.nix

{ pkgs ? import <nixpkgs> {} }:

(pkgs.buildFHSUserEnv {
  name = "arduino";
  targetPkgs = pkgs: (with pkgs; [ 
      arduino
      zlib 
      (python3.withPackages (p: with p; [ pyserial avahi ]))      
    ]);
  runScript = "arduino";
  profile="export _JAVA_AWT_WM_NONREPARENTING=1"; #This fixes odd JRE Rendering issues with the Arduin IDE GUI
}).env

As far as i know it does not really matter where you put this script or if there is a dedicated place i have just put mine with all of my other configs untill a better solution makes itself evident.

But from this point while your in the same directory as your default.nix you can execute nix-shell and the arduino IDE will fire right up and all your dynamic linking issues should be a thing of the past, if you like you can modify this nix to take parameters and use the CLI tools as well.

Happy Coding <3

Bonus Issue

Now with all that fixed i did run into another issue and this one is not specifically Nix related it has more to do with iptables and the nix CHAIN, As i said i wanted to use OTA to update the ESP-01 and the Arduino IDE has a nice feature for that so i dont have to build and send to a webserver but push directly to the ESP.

The issue if its not obvious at this point is once the OTA firmware i wrote was flashed to the ESP the IDE was not able to find it to solve this issue i did a number of things.

The first thing was add the folowing firewall configuration to my configuration.nix

# Open ports in the firewall.
networking.firewall.allowedTCPPorts = [ 5353 8266 ];
networking.firewall.allowedUDPPorts = [ 5353 8266 ];

Port 5353 is the mDNS port for all services that utilise mDNS and port 8266 cleverly is the default port Arduino uses to flash the 8266 chips by Espressif.

Not that is done i could see the ESP but i was now reciving and error like.

ERROR No Response from Device.

When trying to flash via OTA to solve this i had to do two things because by default the hosts flashport is random and we need to make that targeted.

The first modification is adding a variable to Arduino’s prefrences.txt just append the following.

#~/.Arduino15/prefrences.txt

ota.hostport=8266

Now we need to utilise that variable in .arduino15/packages/esp8266/hardware/esp8266/{Your-EspHardwareTools-Version}/platform.txt.

We need to change the line that looks like

tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"

To

tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" -P "{ota.hostport}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"

This forces the host machine to nolonger randomize the outgoing port and pin it to 8266.

Happy OTA firmware development friends.