HTTP API Request to edit config [RESOLVED]

Hello

Goal: I’m trying to update the IOTAWatt from a raspberry pi using a CURL or Javascript command and I’m trying to figure out how the Request needs to be formatted.

Q.1 I can see that when I add a new Input the POST http://iotawatt.local/edit sends a large file containing all of the configuration data.

However, on the GitHub repo in the handleRequest() function for webServer.cpp I can’t see any route for /edit HTTP_POST, I’m guessing that this command is located somewhere else?

Q.2 In regards to the Form Data content, how is that sent? Is it sent as a file called config.txt which contains the config info in a JSON format?

A word of warning. You should understand fully how this whole process works and have a plan to recover if you upload an invalid configuration file. Otherwise, you will brick it.

You can see the config.txt file with the file manager tool.

File upload is handled in the web server, but the “on” directive is located in setup.cpp.

Yes. Then there is another request /config?update=yes directing the IoTaWatt to process the new config.

1 Like

A word of warning. You should understand fully how this whole process works and have a plan to recover if you upload an invalid configuration file. Otherwise, you will brick it.

I have the device on my desk at the moment, but it will eventually be installed in a remote location. For now I can open up the case, pull out the SD card and replace the config.txt file with a backup if needed.

You can see the config.txt file with the file manager tool.

Yeah I spotted that after I made this, I was able to edit it and everything.

Yes. Then there is another request /config?update=yes directing the IoTaWatt to process the new config.

Do you mean /config?update=reload ?

I read through some of the .htm files on the device and I found uploadConfig() and writeFile() functions. I’ll see if I can make any progress by running that instead. I planned on writing some Javascript anyways so this will probably save me some time.

I think that’s right.

If the issue is configuring remotely, IMO the best way is to use the supplied configuration utility and open up a path to port 80 and use a password to control access. If you are committed to using a Rpi, it might make more sense to just install Nginx on the Rpi and use it as a HTTPS gateway to the IoTaWatt, again with password authorization.

I’m against an Nginx proxy for a few reasons.

  1. The graphical interface is slow to respond on LAN so it’ll probably be much slower on WAN.
  2. Running Nginx would leave the Pi exposed, using something like Dataplicity to access and run a simple script would be more secure.
  3. HTTPS requires management of certs, Certbot would be useful, but it requires a domain name to be linked with the Pi’s public IP. Custom certs are also possible, but then I’d have to add the CA file to any web browser to avoid those annoying Unrecognized CA/Insecure Warnings.
  4. I’m not planning to send many API requests, just once for the initial setup and then whenever something needs to be updated.

I did try using some of the javascript I found in your HTML section, however while I wasn’t getting any error responses and it seemed to upload, the file never changed on the device. I think it has to do with XMLHttpRequest library, I’ve never used it before so I might have missed something.

I tried a simple python3 script (code below) to post the file instead and looks like it does the job, I tried adding just 1 extra CT input to the config and it was updated without a reload (imgs below).

Before and After Upload
iota_post_before iota_post_after

Code

import requests


def post_file(iota_ip):
    # concatenating url string
    url = "http://%s/edit" % iota_ip
    # dictionary object where the config.txt is read in as binary
    files = {"file": open("config.txt", "rb")}
    # post request  is assigned to variable so response code can be printed
    r = requests.post(url, files=files)
    # should print 200
    print(r.status_code)


def main():
    iota_ip = DEVICE_IP_HERE
    post_file(iota_ip)


if __name__ == "__main__":
    main()