davidusb-geek / emhass

emhass: Energy Management for Home Assistant, is a Python module designed to optimize your home energy interfacing with Home Assistant.
MIT License
260 stars 51 forks source link

Flask Return action error logs to webserver #191

Closed GeoDerp closed 4 months ago

GeoDerp commented 4 months ago

In its current status the response message to the action is a status code Ex: https://github.com/davidusb-geek/emhass/blob/78309ad7b2a8f6f280deadec4bca378279476d00/src/emhass/web_server.py#L55 This however doesn't indicate if there was an error during action (and if there was, what was it). This only gives us the information that the action has completed (with an 201 code)

PR #190 implements alert box element that currently only facilitates JSON input format error: https://github.com/davidusb-geek/emhass/blob/78309ad7b2a8f6f280deadec4bca378279476d00/src/emhass/templates/index.html#L200-L203

I believe we could modify the return make_response(msg, 201) to send back a 400 status code with an error log body (ex: as string[]) if something went wrong. we could then tell the JS to present the html alert box with the response error data. (helping the user understand why it crashed without viewing the logs)

js example being:

webserver.py (as an example)

return make_response(["testa","testb","testc"], 400)

index.html

https://github.com/davidusb-geek/emhass/blob/78309ad7b2a8f6f280deadec4bca378279476d00/src/emhass/templates/index.html#L83-L122

to

    async function formAction(action) {
        var data = inputToJson()
        if (data !== 0) { //don't run if there is an error in the data Json
            showChangeStatus("loading") // show loading div for status
            response = await fetch(`{{ basename }}/action/${action}`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify(data), //post can only send data via strings
            }).then(saveStorage()) //save to storage if successful 
            showChangeStatus(response) //replace loading, show tick or cross
        }
        else {
            showChangeStatus("remove") //replace loading, show tick or cross with none 
        }
    }

    //function in control of status icons of post above
    function showChangeStatus(response) {
        var loading = document.getElementById("loader") //element showing status 
        if (response.status === "remove") { //remove status icons
            loading.innerHTML = "";
            loading.classList.remove("loading"); 
        }
        else if (response.status === "loading") { //show loading logo
            loading.innerHTML = "";
            loading.classList.add("loading"); //append class with loading animation styling
        }
        else if (response.status === 201) { //then show a tick 
            loading.classList.remove("loading")
            loading.innerHTML = `<p class=tick>&#x2713;</p>`

        }
        else { //then show a cross 
            loading.classList.remove("loading")
            loading.innerHTML = `<p class=cross>&#x292C;</p>` //show cross icon to indicate an error
             document.getElementById("alert-text").textContent = "\r\n" + (await response.json()).split(',').join("\r\n")  //This assumes the data is a string array 
             document.getElementById("alert").style.display = "block";
        }
    }

Originally posted by @GeoDerp in https://github.com/davidusb-geek/emhass/issues/190#issuecomment-1936914644

Some info I found here: https://flask.palletsprojects.com/en/2.3.x/api/#flask.Flask.make_response

GeoDerp commented 4 months ago

I guess the hardest thing I haven't worked out is how to get in the app log of the action instance

davidusb-geek commented 4 months ago

I'm not certain but possibly some solutions here: https://stackoverflow.com/questions/66277372/writing-flask-console-logs-to-an-html-template-as-and-when-it-appears

GeoDerp commented 4 months ago

Haven't looked into this. It may grab all console logs. I think we want to get just the ones from app.logger (in particular the ones related to the last ran action) although maybe we can filter before we send it out 🤔

If we can get the logs into the form of a string array I can pass it. Just have to work out how.

GeoDerp commented 4 months ago

If I have some spare time I'll take a look at both of these issues I recently created. For now. I'll take a brake 👍