Not specifically node-red oriented, but I have written a script that I use to burn SD cards for Pis, and it was suggested I post it here. It burns one of the standard Raspbian downloads then sets up the wifi SSID and password if required, IP address, and DNS, enables ssh and renames the default user. The idea is that it should be possible to plug the card into the Pi and it should power up and be accessible without further work. I then use Ansible to install and configure node-red and other packages as required but that is a separate issue.
It is written in ruby but could easily be rewritten in your language of choice.
It runs on Ubuntu, but should not need much work to run on a different Linux. Windows would be a bit tricker I think.
If you try it be careful to pay attention to the messages before telling it to do the burn. It shows you the mounted devices so you can ensure that you are burning to the correct device and asks for confirmation twice, but if you tell it to write to the wrong device then it may overwrite your system disk. So please convince yourself it is doing the right thing before running it. I accept no liability for any disasters that may ensue.
#!/usr/bin/env ruby
require 'io/console'
# burn and build a pi SD card given
# raspbian image zip file, name of pi to build and sd_device (eg sdb or mmcblk0)
default_user = "userx"
default_router = "192.168.1.1"
default_ssid = "MySSID"
default_dns = default_router
devices = Hash[
"piz002" => {:interface => "wlan0", :ip => "192.168.1.81", :dns => "192.168.1.1",
:user => "userx", :router => "192.168.1.1", :ssid => "MySSID"},
"pixxx" => {:interface => "wlan0", :ip => "192.168.1.20", :dns => "192.168.1.1", :user => "userx"},
"pi003" => {:interface => "wlan0", :ip => "192.168.1.82"}
]
def configure_device( name, interface, ip, user, dns, router, ssid )
puts "Enter wifi password"
password = STDIN.noecho(&:gets).chomp
# probably don't need sudo here as script run with sudo, also probably don't need the chmod
#system("chmod 664 /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo 'country=GB' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo 'network={' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo ' ssid=\"#{ssid}\"' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo ' psk=\"#{password}\"' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo ' key_mgmt=WPA-PSK' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
system("echo '}' >> /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
#system("chmod 644 /media/userx/rootfs/etc/wpa_supplicant/wpa_supplicant.conf")
# add interface to /etc/dhcpcd.conf
system("echo 'interface #{interface}' >> /media/userx/rootfs/etc/dhcpcd.conf")
system("echo 'static ip_address=#{ip}/24' >> /media/userx/rootfs/etc/dhcpcd.conf")
system("echo 'static routers=#{router}' >> /media/userx/rootfs/etc/dhcpcd.conf")
system("echo 'static domain_name_servers=#{dns}' >> /media/userx/rootfs/etc/dhcpcd.conf")
# change hostname in /etc/hosts and /etc/hostname
["/media/userx/rootfs/etc/hosts","/media/userx/rootfs/etc/hostname"].each do |file_name|
system("sed -i 's/raspberrypi/#{name}/g' #{file_name}")
end
# change default username from pi to user
["/media/userx/rootfs/etc/passwd", "/media/userx/rootfs/etc/shadow"].each do |file_name|
cmd="sed -i 's/pi:/#{user}:/g' #{file_name}"
system("echo '#{cmd}'")
system("sed -i 's/pi:/#{user}:/g' #{file_name}")
end
system("sed -i 's/:pi$/:#{user}/g' /media/userx/rootfs/etc/group")
system("sed -i 's/^pi:/#{user}:/g' /media/userx/rootfs/etc/group")
# rename home folder
system("mv /media/userx/rootfs/home/pi /media/userx/rootfs/home/#{user}")
# enable ssh
system( "touch /media/userx/boot/ssh" )
# make ssh keys
system("mkdir /media/userx/rootfs/home/#{user}/.ssh")
system("ssh-keygen -N '' -t rsa -f /media/userx/rootfs/home/#{user}/.ssh/id_rsa")
# change ownership to user
system("chown -R #{user}:#{user} /media/userx/rootfs/home/userx/.ssh")
end
def burn( src, sd_device )
answer = false
puts `lsblk|grep 'sd\\|mmc'`
puts "Check the SD card is #{sd_device}. Ok y/n?"
ans = STDIN.gets.chomp # have to use STDIN to stop it picking up the command line
if ans == 'y'
puts "Are you sure you want to burn #{src} to #{sd_device}? this will ERASE #{sd_device}!!!"
ans = STDIN.gets.chomp
if ans == 'y'
puts "Burning #{sd_device} from #{src}"
cmd = "unzip -p #{src} |dd of=/dev/#{sd_device} bs=4M status=progress conv=fsync"
answer = system( cmd )
end
end
return answer
end
if ENV["USER"] != "root"
puts "Script must be run with sudo"
exit
end
# should be exactly three parameters
if ARGV.length != 3 then
puts "Usage: sudo pi_burn_and_rebuild zipfile pi_id sd_device (eg sdb or mmcblk0)"
puts "Where zipfile is the raspbian image zip file and pi_id is pi to burn, eg pi002"
else
host_name = ARGV[1]
sd_device = ARGV[2]
device = devices[host_name]
# check device exists in table
if !device
puts "Unknown device #{host_name}"
else
user = device[user] ? device[user] : default_user
dns = device[dns] ? device[dns] : default_dns
router = device[router] ? device[router] : default_router
ssid = device[ssid] ? device[ssid] : default_ssid
puts "device: #{device}, user: #{user}, dns: #{dns}, router: #{router}, ssid: #{ssid}"
if burn(ARGV[0], sd_device)
puts "Burn succeeded",
"Unplug the card, wait a few seconds then plug in again, wait till it mounts then hit enter"
STDIN.gets
configure_device( host_name, device[:interface], device[:ip], user, dns, router, ssid )
puts " ",
"Now unmount the SD card.",
" ",
"Don't forget to change the password (passwd) from raspberry after connecting as #{user}"
else
puts "Burn failed or aborted"
end
end
end