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

index/style added runtime parameter dictionary inputs #190

Closed GeoDerp closed 4 months ago

GeoDerp commented 4 months ago

Related to: https://github.com/users/davidusb-geek/projects/1/views/1?pane=issue&itemId=52545404

Changed

Examples

(Dark mode) Input: Box Screenshot from 2024-02-08 23-06-16 Input: List Screenshot from 2024-02-08 23-06-04

GeoDerp commented 4 months ago

This isn't polished yet, may still come back tomorrow and tweak. Would appreciate any help.

codecov[bot] commented 4 months ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Comparison is base (195e774) 89.84% compared to head (923d4e2) 89.84%. Report is 1 commits behind head on master.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #190 +/- ## ======================================= Coverage 89.84% 89.84% ======================================= Files 6 6 Lines 1645 1645 ======================================= Hits 1478 1478 Misses 167 167 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

davidusb-geek commented 4 months ago

That actually look really really nice. This could be very helpful for testing. Nice work! You tell me when is ready so we can merge.

GeoDerp commented 4 months ago

That actually look really really nice. This could be very helpful for testing. Nice work! You tell me when is ready so we can merge.

In theory it's ready to go now. However, it will probably be good for me to have a look at it tomorrow morning and polish any possible bugs.

purcell-lab commented 4 months ago

I couldn't see how to comment on the project board entry, so I'll put some thoughts here.

I help a lot of new users onboard with EMHASS.

From a user interface (UI) perspective, they load up EMHASS, then they go to this web page and start hitting the first button PerfectOpt (which doesn't appear to do anything), then they hit the second button DayAheadOpt (which also doesn't appear to do anything), then they randomly hit the ML buttons, which certainly doesn't appear to do anything.

I think there are too many confusing options on this front page and would welcome an 'Advanced' tab that 'hides' the functions that require configuration.

The workflow in my mind would be to have a the Post Data box up front, as people need to inject values first, I like the second concept with a different box for each key. Then have a DayAheadOpt button, then have a Publish button.

Some sort of running log or user feedback when which of these steps is selected would also be really valuable, because as it stands there is zero feedback when a button is pressed.. If possible having the log running in a side bar would be ideal. I have a really ugly hack using iframes to display the log next to some buttons, but that would be far superior in the EMHASS ingress page.

image

GeoDerp commented 4 months ago

These are good ideas.

I have actually thought about the logger on the page myself. However I have currently no idea how to achieve that.

pseudo code thought would be:

I wonder if you can get all app.logger logs and append lines of it has changed

purcell-lab commented 4 months ago

However I have currently no idea how to achieve that.

Something like the Logger capability on the devices would be ideal.

Screenshot_20240209-121759

davidusb-geek commented 4 months ago

I couldn't see how to comment on the project board entry, so I'll put some thoughts here.

I just added you to the project members. But we can continue our discussion here is ok.

From a user interface (UI) perspective, they load up EMHASS, then they go to this web page and start hitting the first button PerfectOpt (which doesn't appear to do anything), then they hit the second button DayAheadOpt (which also doesn't appear to do anything), then they randomly hit the ML buttons, which certainly doesn't appear to do anything. I think there are too many confusing options on this front page and would welcome an 'Advanced' tab that 'hides' the functions that require configuration.

Thank you Mark for the REX, this is very important to improve!

I think that yes maybe we can hide some buttons and the text box in an "advanced" tab to avoid confusing users with all these options.

The workflow in my mind would be to have a the Post Data box up front, as people need to inject values first, I like the second concept with a different box for each key. Then have a DayAheadOpt button, then have a Publish button.

Agree, at least the "day-ahead" and "publish" buttons and the text box to add more data shoul be up front. Also we should take one step at a time. I think that the text box functionality that @GeoDerp just added is great as it is right now and I really like the two options: a whole dictionary of data and the list option.

I have actually thought about the logger on the page myself. However I have currently no idea how to achieve that.

Of course that a logging functionality should be great. But I don't think it is completely necessary. I mean you can always have two browser tabs open, one for the webui and one for the logger. But I do agree that we could add some responsiveness when pushing the buttons on the webui. An easy solution would be just to post a little message something like "Successful POST request sent to day-ahead optimization task" for example. The logging functionality is great but requires a lot much more effort.

GeoDerp commented 4 months ago

Will require testing and refinding. Added the following capabilities:

Looks Something like this: (dark theme) on success Screenshot from 2024-02-09 23-43-28
Json error and post loading Screenshot from 2024-02-09 23-43-17

GeoDerp commented 4 months ago

I may want to strengthen the null exceptions with input lists. Otherwise this works (just forces one empty list to be on screen at all times) Will like to spend more time testing strengthening every scenario (like if local storage is disabled). Any assistance for the bug hunting will be appreciated.

GeoDerp commented 4 months ago

Update: found a few bugs. Will keep you posted when I fix them

GeoDerp commented 4 months ago

I think Im pritty happy now. For future reference. I believe we could modify the return make_response(msg, 201) to send back error log data if something went wrong. we could then tell the js to present the html alert box with the response error data.

js example being:

    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.status) //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(status) {
        var loading = document.getElementById("loader") //element showing status 
        if (status === "remove") { //show loading logo
            loading.innerHTML = "";
            loading.classList.remove("loading"); //append class with loading animation styling
        }
        else if (status === "loading") { //show loading logo
            loading.innerHTML = "";
            loading.classList.add("loading"); //append class with loading animation styling
        }
        else if (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>`
        }
    }

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") { //show loading logo
            loading.innerHTML = "";
            loading.classList.remove("loading"); //append class with loading animation styling
        }
        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>`
             document.getElementById("alert-text").textContent = "\r\n" + response.msg //or what the dict  response key is
             document.getElementById("alert").style.display = "block";
        }
    }
GeoDerp commented 4 months ago

Feel free to set this as an issue so we can keep track of it if desired.

I think Im pritty happy now. For future reference. I believe we could modify the return make_response(msg, 201) to send back error log data if something went wrong. we could then tell the js to present the html alert box with the response error data.

js example being:

    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.status) //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(status) {
        var loading = document.getElementById("loader") //element showing status 
        if (status === "remove") { //show loading logo
            loading.innerHTML = "";
            loading.classList.remove("loading"); //append class with loading animation styling
        }
        else if (status === "loading") { //show loading logo
            loading.innerHTML = "";
            loading.classList.add("loading"); //append class with loading animation styling
        }
        else if (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>`
        }
    }

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") { //show loading logo
            loading.innerHTML = "";
            loading.classList.remove("loading"); //append class with loading animation styling
        }
        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>`
             document.getElementById("alert-text").textContent = "\r\n" + response.msg //or what the dict  response key is
             document.getElementById("alert").style.display = "block";
        }
    }
davidusb-geek commented 4 months ago

Feel free to set this as an issue so we can keep track of it if desired.

Could you please open the issue your self, or better add a new card with this task to the kanban. I'm not sure to completely understand the issue

davidusb-geek commented 4 months ago

Merging and further testing...