mfaust78 / AmtronXtraModbus

Use Home assistant to get data from your Amtron Xtra / Premium
7 stars 1 forks source link

Is "Total Energy" also somewhere available? #2

Closed redlefloh closed 3 months ago

redlefloh commented 3 months ago

Hi @mfaust78, just a quick question, maybe you know, is the "Total Energy" of the Wallbox also somewhere available over modbus? It is available on the Service Interface (internal webpage) of the Wallbox, so I could also scrape it there, but I thought I ask the expert first if it maybe is also available via modbus, just not documented. Thanks!

Screenshot 2024-05-25 at 23 57 32
mfaust78 commented 3 months ago

Hi @redlefloh, unfortunately the Total Energy is not exposed over Modbus (it is not listed in Mennekes Modbus Description). The only Energy that is exposed is the Energy per Session (from plug-in to plug-out) which I named "Amtron Energy" and is named "Charging session meter count" in the Modbus Documentation. If found it to be the more interesting value anyway and adding up the sessions in HA or other tools is easy.

redlefloh commented 3 months ago

@mfaust78 yes, agree, I actually created a utility meter based on "Charging session meter count". And scarping the Mennekes website is actually quite challenging, it's pretty bad HTML/JS code code, multiscrape is failing with the login, but I was able to do it via puppeteer. I also created a pupeteer script that can automatically reboot the wallbox since sometimes the modbus connection actually dies.

Here are the two puppeteer scripts:

Scrape Total Energy (mennekes_total_energy.js):

// Puppeteer script to scrape the total energy value from the Mennekes Amtron XTRA Wallbox 
// by going to the internal website of the wallbox and then scraping the "dataElementHCME" value 
// Install node.js and puppeteer and then run this scriot with "node mennekes_total_energy.js"

const mennekes_url = 'http://192.168.xxx.xxx:25000' // URL of your Mennekes Amtron Xtra Wallbox
const mennekes_pin = 'xxxxxx'  // PIN of your Mennekes Amtron Xtra Wallbox

const puppeteer = require('puppeteer'); // v22.0.0 or later

(async () => {
    const browser = await puppeteer.launch({
        executablePath: '/usr/bin/chromium-browser',
        headless: true
    });

    const page = await browser.newPage();
    const timeout = 5000;
    page.setDefaultTimeout(timeout);

    {
    const targetPage = page;
    await targetPage.setViewport({
        width: 1038,
        height: 1102
    })

    const promises = [];
    const startWaitingForEvents = () => {
        promises.push(targetPage.waitForNavigation());
    }
    startWaitingForEvents();
    await targetPage.goto(mennekes_url);
    await Promise.all(promises);

    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(User or Installation PIN)'),
        targetPage.locator('#loginPinInput'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginPinInput\\"])'),
        targetPage.locator(':scope >>> #loginPinInput')
    ])
        .setTimeout(timeout)
        .click({
        offset: {
            x: 88.5,
            y: 4.34375,
        },
        });

    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(User or Installation PIN)'),
        targetPage.locator('#loginPinInput'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginPinInput\\"])'),
        targetPage.locator(':scope >>> #loginPinInput')
    ])
        .setTimeout(timeout)
        .fill(mennekes_pin);

    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(Login[role=\\"button\\"])'),
        targetPage.locator('#loginFormSubmit'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginFormSubmit\\"])'),
        targetPage.locator(':scope >>> #loginFormSubmit')
    ])
        .setTimeout(timeout)
        .click({
        offset: {
            x: 51.6640625,
            y: 18.84375,
        },
        });

        const sleep = ms => new Promise(res => setTimeout(res, ms));

        await sleep(3000);

        const text = await page.evaluate(() => {
            const el = document.querySelector('#dataElementHCME')
            return el.innerText
        })

        console.log(text)

        const fs = require('fs');
        fs.writeFileSync('/home/pi/docker/homeassistant/mennekes_amtron_total_energy.txt', text);

        await browser.close();

    }

})().catch(err => {
    console.error(err);
    process.exit(1);
});

Reboot the Mennekes Wallbox (mennekes_reboot.js):

// Puppeteer script to automatically reboot a Mennekes Amtron XTRA Wallbox by going to the internal
// website of the wallbox and then to the Systems page and clicking on "Reboot AMTRON"
//
// Install node.js and puppeteer and then run this scriot with "node mennekes_reboot.js"

const mennekes_url = 'http://192.168.xxx.xxx:25000' // URL of your Mennekes Amtron Xtra Wallbox
const mennekes_pin = 'xxxxxx'  // PIN of your Mennekes Amtron Xtra Wallbox

const puppeteer = require('puppeteer'); 

(async () => {
    const browser = await puppeteer.launch({
        executablePath: '/usr/bin/chromium-browser',
        headless: true
    });

    const page = await browser.newPage();
    const timeout = 5000;
    page.setDefaultTimeout(timeout);

    {
    const targetPage = page;
    await targetPage.setViewport({
        width: 1038,
        height: 1102
    })

    const promises = [];
    const startWaitingForEvents = () => {
        promises.push(targetPage.waitForNavigation());
    }
    startWaitingForEvents();
    console.log("Open Page...");
    await targetPage.goto(mennekes_url);
    await Promise.all(promises);

    console.log("Goto Login...");
    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(User or Installation PIN)'),
        targetPage.locator('#loginPinInput'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginPinInput\\"])'),
        targetPage.locator(':scope >>> #loginPinInput')
    ])
        .setTimeout(timeout)
        .click({
        offset: {
            x: 88.5,
            y: 4.34375,
        },
        });

    console.log("Entering Password...");    
    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(User or Installation PIN)'),
        targetPage.locator('#loginPinInput'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginPinInput\\"])'),
        targetPage.locator(':scope >>> #loginPinInput')
    ])
        .setTimeout(timeout)
        .fill(mennekes_pin);

    console.log("Clicking Login...");
    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(Login[role=\\"button\\"])'),
        targetPage.locator('#loginFormSubmit'),
        targetPage.locator('::-p-xpath(//*[@id=\\"loginFormSubmit\\"])'),
        targetPage.locator(':scope >>> #loginFormSubmit')
    ])
        .setTimeout(timeout)
        .click({
        offset: {
            x: 51.6640625,
            y: 18.84375,
        },
        });

    console.log("Going to the Systems Page...");

    await puppeteer.Locator.race([
        targetPage.locator('::-p-aria(System)'),
        targetPage.locator('#header li:nth-of-type(5) > a'),
        targetPage.locator('::-p-xpath(//*[@id=\\"primaryNav\\"]/ul/li[5]/a)'),
        targetPage.locator(':scope >>> #header li:nth-of-type(5) > a')
    ])
        .setTimeout(timeout)
        .click({
        offset: {
            x: 23.7265625,
            y: 10.875,
        },
        });
    console.log("Showing Systems Page...");
    await page.evaluate(`showPage("System")`);

        const sleep = ms => new Promise(res => setTimeout(res, ms));

        console.log("Waiting for page to finish loading...");
        await sleep(3000);

    console.log("Clicking Reboot Button...");
    await targetPage.click('input[value="Reboot AMTRON"]');
    await page.screenshot({
        path: 'screenshot.jpg'
    }); 

        await browser.close();

        console.log("Done.");
    }

})().catch(err => {
    console.error(err);
    process.exit(1);
});

Instructions to install node.js and puppeteer:

Create a puppeteer directory in /config

cd /home/pi/docker/homeassistant
mkdir puppeteer
cd puppeteer 

Download and run the node install script: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash nvm install 20

Install Puppeteer: npm -i puppeteer

Important, in order to run on a RasPi you need:

const browser = await puppeteer.launch({
        executablePath: '/usr/bin/chromium-browser',
        headless: true
});

Run a node.js script via ssh on the host computer from within a docker container

If you run Home Assistant in a docker container, you can't run scripts on the host computer. Therefore you need to use the trick to ssh from the docker container into your hostcontainer and then execute a script. See instructions here