Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTA update via platformio not working and Preferences.h questions #72

Open
PPKGroup opened this issue Jan 20, 2022 · 25 comments
Open

OTA update via platformio not working and Preferences.h questions #72

PPKGroup opened this issue Jan 20, 2022 · 25 comments

Comments

@PPKGroup
Copy link

Hi,

I'm using platformio (on VSC) and Win10 for programming of my device.
In my platformio.ini file I have placed the following code:
[env:WiFi]
upload_protocol = espota
upload_port = 10.100.8.60

When I try to build and upload, I get the following error:

Uploading .pio\build\WiFi\firmware.bin
14:18:41 [DEBUG]: Options: {'esp_ip': '10.100.8.60', 'host_ip': '0.0.0.0', 'esp_port': 3232, 'host_port': 48565, 'auth': '', 'image': '.pio\build\WiFi\firmware.bin', 'spiffs': False, 'debug': True, 'progress': True, 'timeout': 10}
14:18:41 [INFO]: Starting on 0.0.0.0:48565
14:18:41 [INFO]: Upload size: 1284432
Sending invitation to 10.100.8.60 ..........
14:18:41 [ERROR]: No response from the ESP
*** [upload] Error 1

If I browse to the device e.g. http://10.100.8.60/update, the ElegantOTA web page is displayed.

Any ideas on how to get this to work through the platformio environment?

I read somewhere on the RNT website that ElegantOTA overwrites the spiffs and Preferences (NVS) flash storage.
In platformio is there a way of limiting where ElegantOTA writes to?

Thanks,
Neil.

@viktak
Copy link

viktak commented Sep 13, 2023

I would also like to have this feature implemented... It was sooo easy to use it before Asynwebserver...

@normen
Copy link

normen commented Sep 22, 2023

For me it works like this with the extra script, note the URL:

extra_scripts = platformio_upload.py
upload_protocol = custom
upload_url = http://192.168.123.123/ota/upload

Edit: Wait, no. It just gives an "OK" but the firmware isn't written 😕

@mindsuru
Copy link
Contributor

mindsuru commented Oct 19, 2023

ive had the same problem. For me it helped to use these platformio.ini configurations

extra_scripts = platformio_upload.py
upload_protocol = custom
upload_url = http://[IP or hostname] ; eg http://192.168.178.20

and i had to modify the platformio_upload.py file, and excuse me, i haven't been programming very long. It's not pretty but it works for me.
It looks like something was changed in the ElegantOTA library because of the GET and POST requests, so the script encounters problems. So I didn't do more than mimic the behavior of the browser. And thats it:


# Allows PlatformIO to upload directly to ElegantOTA
#
# To use:
# - copy this script into the same folder as your platformio.ini
# - set the following for your project in platformio.ini:
#
# extra_scripts = platformio_upload.py
# upload_protocol = custom
# upload_url = <your upload URL>
# 
# An example of an upload URL:
# upload_URL = http://192.168.1.123

import requests
import hashlib
from urllib.parse import urlparse
Import("env")

try:
    from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
    from tqdm import tqdm
except ImportError:
    env.Execute("$PYTHONEXE -m pip install requests_toolbelt")
    env.Execute("$PYTHONEXE -m pip install tqdm")
    from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
    from tqdm import tqdm

def on_upload(source, target, env):
    firmware_path = str(source[0])
    upload_url = env.GetProjectOption('upload_url')

    with open(firmware_path, 'rb') as firmware:
        md5 = hashlib.md5(firmware.read()).hexdigest()

        parsed_url = urlparse(upload_url)
        host_ip = parsed_url.netloc

        # Führe die GET-Anfrage aus
        start_url = f"{upload_url}/ota/start?mode=fr&hash={md5}"
        # start_response = requests.get(start_url)
        start_headers = {
            'Host': host_ip,
            'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0',
            'Accept': '*/*',
            'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
            'Accept-Encoding': 'gzip, deflate',
            'Referer': f'{upload_url}/update',
            'Connection': 'keep-alive'
            }

        start_response = requests.get(start_url, headers=start_headers)
        
        # Drucke Anfrage- und Antwortkopfzeilen für die GET-Anfrage
        # print("GET Anfragekopfzeilen:", start_response.request.headers)
        # print("GET Antwortkopfzeilen:", start_response.headers)

        if start_response.status_code != 200:
            print("Start-Request fehlgeschlagen " + str(start_response.status_code))
            return

        firmware.seek(0)
        encoder = MultipartEncoder(fields={
            'MD5': md5,
            'firmware': ('firmware', firmware, 'application/octet-stream')}
        )

        bar = tqdm(desc='Upload Progress',
                   total=encoder.len,
                   dynamic_ncols=True,
                   unit='B',
                   unit_scale=True,
                   unit_divisor=1024
                   )

        monitor = MultipartEncoderMonitor(encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))

        post_headers = {
            'Host': host_ip,
            'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0',
            'Accept': '*/*',
            'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
            'Accept-Encoding': 'gzip, deflate',
            'Referer': f'{upload_url}/update',
            'Connection': 'keep-alive',
            'Content-Type': monitor.content_type,
            'Content-Length': str(monitor.len),
            'Origin': f'{upload_url}'
        }


        response = requests.post(f"{upload_url}/ota/upload", data=monitor, headers=post_headers)
        
        # Drucke Anfrage- und Antwortkopfzeilen für die POST-Anfrage
        # print("POST Anfragekopfzeilen:", response.request.headers)
        # print("POST Antwortkopfzeilen:", response.headers)

        bar.close()

        if response.status_code != 200:
            print("Upload fehlgeschlagen")
        else:
            print("Upload erfolgreich", response.text)

            
env.Replace(UPLOADCMD=on_upload)

@ayushsharma82
Copy link
Owner

@mindsuru The internal API of ElegantOTA indeed got changed to provide a much better & stable experience. Your fix looks promising! It was a community PR that added it in past that's why it wasn't updated with V3.

If you don't mind, can you open a PR that fixes the platformio_upload.py script?

@mindsuru
Copy link
Contributor

mindsuru commented Oct 19, 2023

Thanks,
and okay, I'll give it a try. I'm not that familiar with GitHub yet, but it should work out somehow. I'll read up on it.

I changed the python file slightly. Now you can use it with the old configuration in your platformio.ini

@viktak
Copy link

viktak commented Oct 30, 2023

@mindsuru For me the version you have here does not work. It gives the following error, then quits:

....
Uploading .pio\build\esp32\firmware.bin
Start-Request fehlgeschlagen 401

Seems to me that it cannot find the OTA page... This is the relevant part of my platformio.ini:

extra_scripts = 
    pre:../../scripts/preIncrementBuildNumber.py
    platformio_upload.py
upload_protocol = custom
upload_url = http://192.168.123.137

As you can see I have an extra script running, but I don't suppose that would be an issue as the behavior is that same when I remove it.
If I can help testing any new version of your script, don't hold back :)

@bartoszzajac
Copy link

@mindsuru @ayushsharma82 When can we expect PR and merge?

@mindsuru
Copy link
Contributor

@viktak is your device reachable with this ip you‘ve choosen in your platformio.ini file?

@ayushsharma82
Copy link
Owner

@mindsuru @ayushsharma82 When can we expect PR and merge?

It has been merged but yet to be released.

@ayushsharma82
Copy link
Owner

@viktak is your device reachable with this ip you‘ve choosen in your platformio.ini file?

I guess he's using authentication that's why response code was '401' which means 'Unauthorized'. The script might need adjustments to work with authentication enabled.

@viktak
Copy link

viktak commented Nov 22, 2023

Yes, the device is reachable, all other functions of the asyncwebserver and elegantota are all working.

@viktak
Copy link

viktak commented Nov 22, 2023

@viktak is your device reachable with this ip you‘ve choosen in your platformio.ini file?

I guess he's using authentication that's why response code was '401' which means 'Unauthorized'. The script might need adjustments to work with authentication enabled.

Yessss, I definitely use authentication.

But the authentication is added on a per page basis, i.e. for each of the protected pages (not all of them are) I add this line:

                if(!request->authenticate(ADMIN_USERNAME, appSettings.adminPassword))
                    return request->requestAuthentication();

So the pages that don't use authentication should work just fine. In fact, those pages of mine that do not require authentication work fine.

@mindsuru
Copy link
Contributor

Okay good to know. I will have a look on it. But unfortunatly i‘m ill right now. It may take a bit.

@viktak
Copy link

viktak commented Nov 23, 2023

Okay good to know. I will have a look on it. But unfortunatly i‘m ill right now. It may take a bit.

Get well soon, that's the priority!

@mindsuru
Copy link
Contributor

i think thats it. now both upload methods should work. regardless of whether you use the encrypted or non-encrypted method.
i opened a pull request for that change

@viktak
Copy link

viktak commented Nov 24, 2023

@mindsuru Yes, it is now working.
I just checked the version in the pull request, and at first it failed with a message that there was no username defined, but once I defined all the credentials the upload worked flawlessly.
Here are all the relevant additions in platformio.ini I had to make it work:

extra_scripts = 
    platformio_upload.py

build_flags =
    '-DELEGANTOTA_USE_ASYNC_WEBSERVER = 1'

lib_deps =
    ottowinter/ESPAsyncWebServer-esphome @ ^3.1.0
    esphome/AsyncTCP-esphome @ ^2.0.1
    ayushsharma82/ElegantOTA @ ^3.1.0

upload_protocol = custom
upload_url = http://w.x.y.z
username = username 
password = password 

@viktak
Copy link

viktak commented Nov 24, 2023

One more request, perhaps it is possible to rename the expected variables from this:

upload_url = http://w.x.y.z
username = username 
password = password 

to this:

custom_upload_url = http://w.x.y.z
custom_username = username 
custom_password = password 

This is to get rid of those pesky PlatformIO warning:

Warning! Ignore unknown configuration option `upload_url` in section [env:esp32]
Warning! Ignore unknown configuration option `username` in section [env:esp32]
Warning! Ignore unknown configuration option `password` in section [env:esp32]

@mindsuru
Copy link
Contributor

sure and thanks for this information

@viktak
Copy link

viktak commented Dec 29, 2023

I have been using the updated script for a couple of months now on various projects. Here are my observations:

  1. Doing an update from the /update page works all the time, every time, be it the firmware or the spiffs.
  2. From PlatformIO, uploading the code works perfectly all the time, every time.
  3. However, uploading the spiffs from PlatformIO is a hit and miss for me, and I haven't figured out what the problem might be. I haven't even noticed a pattern, to be honest. Sometimes it works, sometimes it fails during upload, sometimes it goes fine to 100%, then it says:
Upload Progress: 100%|██████████| 1.50M/1.50M [00:07<00:00, 205kB/s]

Upload faild.
Server response: Failed to write chunked data to free space

or it complains about the magic byte (I can't remember the exact message...)
4. Some typos in the console: "faild" *3 and "successfull" *1

Copy link
Contributor

github-actions bot commented Jul 2, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Jul 2, 2024
@viktak
Copy link

viktak commented Jul 5, 2024

I still have this issue.

@github-actions github-actions bot removed the Stale label Jul 9, 2024
Copy link
Contributor

github-actions bot commented Aug 9, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Aug 9, 2024
@viktak
Copy link

viktak commented Aug 9, 2024

I still have this issue.

@github-actions github-actions bot removed the Stale label Aug 10, 2024
Copy link
Contributor

github-actions bot commented Sep 9, 2024

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Sep 9, 2024
@viktak
Copy link

viktak commented Sep 9, 2024

I still have this issue.

@github-actions github-actions bot removed the Stale label Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants