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

Energy management/calculations #3478

Open
jlaur opened this issue Jan 7, 2023 · 64 comments
Open

Energy management/calculations #3478

jlaur opened this issue Jan 7, 2023 · 64 comments
Labels
enhancement An enhancement or new feature of the Core

Comments

@jlaur
Copy link
Contributor

jlaur commented Jan 7, 2023

I'm creating this issue to start brainstorming ideas which may or may not grow into something. For starters, I will share some unstructured thoughts, which could grow into something structured and potentially into something that could be designed and implemented.

Let me start out by sharing some links which can shed some light into where I'm coming from with this:

My initial need is integration to services providing future energy prices. After that, having these prices, I would like to be able to perform calculations. These calculations should be implemented once with a common interface, no matter from which service the prices were obtained. I wonder, from an architectural point of view, if this already means something is needed within openhab-core, since addons cannot depend on other addons? For example, core could provide some interfaces and calculations, while addons could integrate various API's implementing such interface.

Now really brainstorming/dreaming. For the dishwasher example, I logged energy consumption during our most frequently used program and manually mapped that into a timetable in a rule. Considering being able to select the last run specific program on some device (having an energy consumption channel which can be persisted) and map that into another timeslot to calculate the price of that, or having the ideal timeslot calculated automatically within some boundaries. I guess this is just a use-case for the price integrations and calculations and an application which should be built outside of openHAB itself, but just wanted to mention this, so that the parts needed for this could emerge.

I now also have almost real-time logging of the power consumption in my house (see third link above) provided a current power (W) as well as accumulated energy consumed (kWh). The accumulated value is updated once per hour, and current power is updated every 10 seconds. With this data I would like to be able to create a graph like this (screenshot from AMS reader):

image

For this some post-processing is needed, since I receive the kWh data like this:

2023-01-07 21:00:07.940 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Omnipower_Accumulated' changed from 14609.85 kWh to 14610.24 kWh

i.e. as totals, not hourly contributions. So (14610.24-14609.85) kWh = 0.39 kWh from this log example, which is shown as last bar on the graph above. I'm not sure what is the best approach for doing this, but again it would be nice with something consistent and reusable.

I will update this issue with additional thoughts and knowledge from all of you.

I'm currently considering providing a small binding fetching data from EnergiDataService which is a Danish service providing prices. Yesterday I was also able to receive the same prices from ENTSO-E, but in EUR. So this could reach a broader audience, but would additionally require integration to online currency exchange rates to have conversion to local currencies. Currency question: Do we have any kind of currency handling in openHAB?

@jlaur jlaur added the enhancement An enhancement or new feature of the Core label Jan 7, 2023
@lsiepel
Copy link
Contributor

lsiepel commented Jan 7, 2023

As other tools as Grafana are way better in visualizing data, i have seen many users do something like this (including myself):

  1. Persist an openHAB channel with energy price information (x euro per kw/h from datestamp x)
  2. Persist power usage. This can be done at several levels; per device, or on total (e.g. P1 monitor on smart meter), usually some rule is involved for post-processing as most bindings/smart meter only record running totall.
  3. Tie data from 1 and 2 together with plain simple SQL and display in Grafana and you have clear insights in hourly costs or even costs of a wash machine run.

But that is just historical. What would the future calculations need to do? Assist with deciding the provider to use? or automated decission to start or delay a power consuming task? Prognoses based on your historicall usage only is not enough, you would need a lot more parameters to train a model.

/me: subscribed to this topic :-)

@jlaur
Copy link
Contributor Author

jlaur commented Jan 7, 2023

What would the future calculations need to do?

See the dishwasher rule example I've provided. I simply program the dishwasher to be finished 7:00 in the morning. The rule will then detect that this has been scheduled and will then calculate the optimal period considering how much power it uses during the program and the future prices. For example, my most used program will use the most power approximately 1:30 into the program and then for the next hour after that. Therefore, for best results, the program needs to be mapped. Assuming linear power consumption for the duration of the program will give very different results.

Assist with deciding the provider to use? or automated decission to start or delay a power consuming task? Prognoses based on your historicall usage only is not enough, you would need a lot more parameters to train a model.

Or something simpler. For example, for the washing machine we use a few more different programs than for the dishwasher, so in this case I haven't mapped any programs yet. However, I have persisted all parameters including the program types and energy consumption. So in theory I could select the last 60 °C cottons program, and the mapping of the program could be done automatically. I could then move this into the future, and the price could be calculated from a period, or the period could be calculated from the lowest price.

@lsiepel
Copy link
Contributor

lsiepel commented Jan 8, 2023

Feeding tasks with details (e.g start/end boundaries, task duration, energy usage profile) to this ‘energy management service’ is one thing(demand). The other can be a bit more complex. The prices from external providers like you said can be obtained. But what about your own energy generators? Solar panels? That may need some weather prognoses etc? Home batteries? May need some expected battery drain.

Prices here (Netherlands) are sort of fixed, and you only pay for the annual nett (from and to the grid substracted) result of power usage. Because of this method, scheduling is not yet important, but it will as these rules have changed per 2025.

What constraints would the internal scheduler have?

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/bringing-electricity-information-from-eloverblik-dk-and-energidataservice-dk-into-openhab/143470/4

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/entsoe-e-binding-for-nordpool-spot-prices/143833/4

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/dishwasher-price-calculation-automation/139207/1

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/dishwasher-price-calculation-automation/139207/4

@masipila
Copy link

masipila commented Feb 10, 2023

@jlaur , here are the calculations that I'm currently using with this solution:
https://community.openhab.org/t/control-a-water-heater-and-ground-source-heat-pump-based-on-cheap-hours-of-spot-priced-electricity/136566/13

I have just recently improved my own solution since we (finally) got our electric vehicle. The content below is therefore is fresh from the oven and more advanced than what I have published in the link above.

1. Fetching the spot price and persisting it as a future-timestamped time series
A pre-requisite for the the calculations below is that the day-ahead spot prices have been fetched and persisted as a future-timestamped time series. I fetch the data from Entso-E API but I won't cover it in this comment since the title of this issue is about the energy calculations, not about fetching the spot prices. My full code for fetching the spot-prices is available in the link above.

2. Finding the cheapest consecutive N-hour window within a given time range
Use cases: I use this method to find the cheapest possible consecutive window for water boiler and charging the car. My rationale for requiring the period to be consecutive hours is that:

  • Water boiler: I do not want to interrupt the water heating process of the boiler. I always allow sufficient amount of hours so that the boiler will heat the water until it hits the max temperature of its own thermostat.
  • Charging the electric vehicle: I haven't actually tried, but I don't think the car would like that the charging would bounce on and off. I anyway need to charge the car only 2-4 hours per night so I find the cheapest window and charge it one go.

I originally used this so that I was searching the cheapest hours from midnight to midnight, but since the electric vehicle came to the picture, I'm now searching the cheapest window between 21 and 06 so that the car will always be ready in the morning.

/**
 * Finds the cheapest 'num' length window on a given range and prepares the on/off control points.
 *
 * @param Date start
 *   Start of the time range. Hour starting at 'start' is included in the range.
 * @param Date stop
 *   Stop of the time range. Hour starting at 'stop' is not included in the range.
 * @param int num
 *   Length of the window to find.
 *
 * @return array
 *   Array of point objects.
 */
function allowCheapWindow(start, stop, num) {
    console.log('spot-price.js: Searching cheapest window...');
    let cheapestSum = 0;
    let startIndex = 0;

    // Read the spot prices from the database. Sort by datetime.
    const prices = influx.getPrices(start, stop);
    prices.sort((a, b) => (a.datetime > b.datetime) ? 1 : -1);

    for (let i = 0; i <= prices.length - num; i++) {
        let sum = 0;
        // Calculate the sum of the hourly prices for the current 'num' hours.
        for (let j = i; j < i + num; j++) {
            let point = prices[j];
            sum += point.value;
        }
        // Initial value for the cheapestSum.
        if (i == 0) {
            cheapestSum = sum;
        }
        if (sum < cheapestSum) {
            cheapestSum = sum;
            startIndex = i;
        }
    }
    console.log('spot-price.js: Cheapest window starts at index: ' + startIndex + ', sum: ' + cheapestSum);

    // Prepare control points.
    let points = [];
    for (let i = 0; i < prices.length; i++) {
        let value = 0;
        if ((i >= startIndex) && (i < startIndex + num)) {
            value = 1;
        }
        let point = {
            datetime: prices[i].datetime,
            value: value
        }
        points.push(point);
    }

    // Return calculated control points
    return points;
}

3. Populating the rest of the day with "OFF" control points
As you can see from the code above, the concept is to generate control points (either 1 or 0) for each hour of the day. I then have a rule that runs at every full hour to see if the actual Switch Item needs to be toggled on or off.

Anyway, the fact that I search for the cheapest car charging window between 21-06 means that I don't have control points from 07:00 onwards. This method allows me to populate 0 value ("off") control points from 07:00 onwards.

/**
 * Blocks the given range regardless of the price.
 *
 * @param Date start
 *   Start of the time range.
 * @param Date stop
 *   Stop of the time range.
 *
 * @return array
 *   Array of point objects.
 */
function blockHours(start, stop) {
    let points = [];

    // Convert from milliseconds to hours
    diff = (stop - start) / 1000 / 3600;

    for (let i = 0; i < diff; i++) {
        let dt = new Date(start);
        dt.setHours(dt.getHours() + i);
        let point = {
            datetime: dt.toISOString(),
            value: 0
        }
        points.push(point);
    }
    return points;
}

4. Finding the individual cheapest hours from a given range, cheap hours do not need to be consecutive.
Use case: Heating of the house

/**
 * Finds 'num' cheapest hours withing the range and prepares the on/off control points.
 *
 * @param Date start
 *   Start of the time range.
 * @param Date stop
 *   Stop of the time range.
 * @param int num
 *   Number of cheap hours to find.
 *
 * @return array
 *   Array of point objects.
 */
function allowCheapHours(start, stop, num) {
    console.log('spot-price.js: Searching cheapest hours...');
    let points = [];

    // Read the spot prices from the database and sort by price.
    const prices = influx.getPrices(start, stop);
    prices.sort((a, b) => (a.value > b.value) ? 1 : -1);

    // Prepare control points.
    for (let i = 0; i < prices.length; i++) {
        let value = (i < num) ? 1 : 0;
        let point = {
            datetime: prices[i].datetime,
            value: value
        }
        points.push(point);
    }

    // Sort points by datetime.
    points.sort((a, b) => (a.datetime > b.datetime) ? 1 : -1);
    return points;
}

5. Finding the individual expensive hours from a given range, hours do not need to be consecutive.
Use case: Like above, but for some devices somebody might want to avoid the most expensive hours.

/**
 * Finds 'num' most expensive hours withing the range and prepares the on/off control points.
 *
 * @param Date start
 *   Start of the time range.
 * @param Date stop
 *   Stop of the time range.
 * @param int num
 *   Number of cheap hours to find.
 *
 * @return array
 *   Array of point objects.
 */
function blockExpensiveHours(start, stop, num) {
    console.log('spot-price.js: Searching most expensive hours...');
    let points = [];

    // Read the spot prices from the database and sort by price.
    const prices = influx.getPrices(start, stop);
    prices.sort((a, b) => (a.value > b.value) ? -1 : 1);

    // Prepare control points.
    for (let i = 0; i < prices.length; i++) {
        let value = (i < num) ? 0 : 1;
        let point = {
            datetime: prices[i].datetime,
            value: value
        }
        points.push(point);
    }

    // Sort points by datetime.
    points.sort((a, b) => (a.datetime > b.datetime) ? 1 : -1);
    return points;
}

6. Finding the individual cheapest hours for heating, balancing the heating throughout the day.
Use case: heating the house when it's very cold and heating must be allowed also during the daytime even if the day hours would be more expensive than some night hours. In other words: when it's -10 C or colder, our the inside temperature of our house will drop too much during the day if I only heat it during the night. In yet another words: I also need to find some "less expensive" hours from the daytime.

First of all, I calculate the needed amount of heating hours based on the weather forecast. The weather forecast has been persisted to a measurement 'fmi_forecast_temperature' with future timestamps.

(Side note: In my own implementation I actually consider both temperature and wind speed of the weather forecast because the house cools down more when it's windy. I use the so called wind chill factor, the "feels like" temperature you can see in weather forecasts, see https://en.wikipedia.org/wiki/Wind_chill#North_American_and_United_Kingdom_wind_chill_index)

I have searched empirically the house-specific formula that is basically "when tomorrow's average temperature is X, I need to allow Y heating hours for the heat pump".

When the number of needed heating hours (Y above) is known / has been calculated, I can use the method below for finding the hours when I will allow the heat pump compressor to be on. Most of the time during this winter I have only heated the house during the night hours (number of slices has been 1) but on very cold days I have split the day to three 8 hour slices and searched the cheapest hours from each slice.

/**
 * Exports.
 */
module.exports = {
    getForecastTemp: getForecastTemp,
    calculateNumberOfHours: calculateNumberOfHours,
    determineHours: determineHours
};

/**
 * Reads forecasted temperatures from the database and calculates an average.
 *
 * @param Date start
 *   Start of the time range.
 * @param Date stop
 *   Stop of the time range.
 *
 * @return float
 *   Average temperature for the range.
 */
function getForecastTemp(start, stop) {
    console.log('nibe.js: Calculating forecasted average temperature...');
    influx = require('kolapuuntie/influx.js');
    const csv = influx.getPoints('fmi_forecast_temperature', start, stop);
    const points = influx.parseCSV(csv, 5, 6);
    let sum = null;
    let avg = null;
    for (let i = 0; i < points.length; i++) {
        sum += points[i].value;
    }
    if (points.length) {
        avg = sum / points.length;
    }
    console.log('nibe.js: average temperature: ' + avg);
    return avg;
}
/**
 * Calculates number of needed hours for given average temperature.
 *
 * @param float temperature
 *   Average temperateure for the day.
 *
 * @return float
 *   Number of hours the heat pump should be allowed to run.
 */
function calculateNumberOfHours(temperature) {
    console.log('nibe.js: Calculating number of ON hours for Nibe...');

    // Early exit if temperature is null.
    if (temperature == null) {
        console.warn('nibe.js: No temperature given! Number of needed hours defaulted to 24!');
        return 24;
    }

    // Calculate curve based on two constant points.
    // y = kx + b
    // x = temperature, y = number of needed hours.
    const p1 = {
        x : -20,
        y : 22
    };
    const p2 = {
        x: 20,
        y: 2
    }
    const k = (p1.y-p2.y) / (p1.x-p2.x);
    const b = p2.y - (k * p2.x);
    console.debug('nibe.js: y = ' + k + 'x + ' + b);

    let y = k * temperature + b;
    if (temperature < p1.x) {
        y = p1.y;
    }
    if (temperature > p2.x) {
        y = p2.y;
    }
    console.log('nibe.js: Number of needed hours: ' + y);
    return y;
}
/**
 * Calculates the on/off hours for the heatpump.
 *
 * @param Date start
 *   Start of the time range.
 * @param Date stop
 *   Stop of the time range.
 * @param int num
 *   Number of hours the heat pump must be on.
 * @param int slices
 *   Divide day into this many slices to balance heating during the day.
 *   Caller is responsible for ensuring that slices is > 0 and < length of the time range.
 *   Example: 2 would result in 2 x 12h slices if the range is 24 hours
 * @paramn float min
 *   Minimum share of heating hours each slice must have.
 *   Caller is responsible for ensuring that the value is a sensible float between 0 and 1.
 *   Example:
 *     Let's say 10h of heating is required and the day is split into 2 slices.
 *     Value 0.1 (10%) means that both slices must have at least 0.1x10h = 1 hour of heating.
 *     The minimum number of hours per slice is rounded down.
 *
 * @return array
 *   Array of point objects.
 */
function determineHours(start, stop, num, slices, min) {
    console.log('nibe.js: Determining on/off hours for Nibe...');
    // console.log("start: " + start);
    // console.log("stop: " + stop);
    // console.log("num: " + num);
    // console.log("slices: " + slices);
    // console.log("min: " + min);
    let selectedHours = [];

    // Read the spot prices from the database and slice the day.
    const prices = influx.getPrices(start, stop);
    const priceSlices = slicePrices(prices, slices);

    // Pick min number of hours from each slice to the final array, but at least 1 per slice.
    let minPerSlice = Math.floor(num*min);
    if (minPerSlice == 0) {
        minPerSlice = 1;
    }

    console.debug('nibe.js: Minimum number of hours for each slice: ' + minPerSlice);
    for (let i = 0; i < priceSlices.length; i++) {
        for (let j = 0; j < minPerSlice; j++) {
            selectedHours.push(priceSlices[i][j]);
            priceSlices[i].splice(j, 1); // Removes price from the slice since it's used.
            num--;
        }
    }

    // console.log("selected hours: ");
    // console.log(selectedHours);

    // Rest of the needed hours can be chosen freely based on the price.
    const merged = mergeSlices(priceSlices);
    // console.log("merged: ");
    // console.log(merged);
    const rest = merged.slice(0, num);
    // console.log("rest: ");
    // console.log(rest);
    selectedHours = selectedHours.concat(rest);
    // console.log("selected");
    // console.log(selectedHours);
    const unselectedHours = merged.slice(num);
    // console.log("unselected");
    // console.log(unselectedHours);
    // Prepare control points.
    const points = preparePoints(selectedHours, unselectedHours);
    // console.log("points");
    // console.log(points);

    return points;
}
/**
 * Slices the spot prices array.
 *
 * @param array prices
 *   Array of spot price objects.
 * @param int slices
 *   Number of slices the 'prices' array should be split.
 *
 * @return array
 *   Array of sliced spot price arrays. Each slice is sorted by spot price.
 */
function slicePrices(prices, slices) {
    const priceSlices = [];
    const n = prices.length;
    const start = 0;
    const length = Math.ceil(n/slices);
    for (let i = 0; i < slices; i++) {
        let slice = prices.slice(i * length, (i+1) * length);
        // Sort slice by prices.
        slice.sort((a, b) => (a.value > b.value) ? 1 : -1);
        priceSlices.push(slice);
    }
    return priceSlices;
}

/**
 * Merges slices to one array.
 *
 * @param array priceSlices
 *
 * @return array
 *   Merged array.
 */
function mergeSlices(priceSlices) {
    let merged = [];
    for (let i = 0; i < priceSlices.length; i++) {
        for (let j = 0; j < priceSlices[i].length; j++) {
            merged.push(priceSlices[i][j]);
        }
    }
    // Sort by prices.
    merged.sort((a, b) => (a.value > b.value) ? 1 : -1);
    return merged;
}
/**
 * Prepares the control points to be written to the database.
 *
 * @param array selectedHours
 * @param array unselectedHours
 *
 * @return array
 *   Array of point objects.
 */
function preparePoints(selectedHours, unselectedHours) {
    let points = [];
    // Value 1 for the selected hours of the day.
    for (let i = 0; i < selectedHours.length; i++) {
        let point = {
            datetime: selectedHours[i].datetime,
            value: 1
        }
        points.push(point);
    }
    // Value 0 for the unselected hours of the day.
    for (let i = 0; i < unselectedHours.length; i++) {
        let point = {
            datetime: unselectedHours[i].datetime,
            value: 0
        }
        points.push(point);
    }
    // Sort by datetime
    points.sort((a, b) => (a.datetime > b.datetime) ? 1 : -1);
    return points;
}

Cheers,
Markus

p.s. I have previously published the code with the following license in the community post linked in the beginning of this comment. It's still my copyright so if parts of this code would end up in openhab, it can be licensed with the license that is used with openhab.

/**
 * Copyright (c) 2022 Markus Sipilä.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/tibber-binding-get-best-price-items-like-awattar-binding/144223/9

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/tibber-binding-get-best-price-items-like-awattar-binding/144223/17

@mstormi
Copy link

mstormi commented Mar 3, 2023

@kaikreuzer
Copy link
Member

Hey guys, I'm now jumping on this train as well, so count me in!
You've all already done amazing work (I'm especially in awe by @masipila rule logics).
I clearly see the energy topic to be a hot one and we should indeed think of new additional concepts to better support such use cases.
FWIW: I have 2 PV systems, planning a 3rd one with a small battery, 2 wallboxes with EVs, a warm water heatpump, electric heating and just subscribed to Tibber (contract starts July 1st). So you see that I have some "demand" for clever energy management. 😆

I tried to read most of your ideas/discussion here, but as it is quite a lot, I certainly will have missed some aspects.

Let me nonetheless try to summarize what I understood what we would ideally need:

  1. A mechanism to store future energy prices (and e.g. also weather forecast data)
  2. A way to declare load curves for dedicated devices
  3. A way to declare and/or calculate future demand of a device (i.e. heating must run 5 hours within the next 12 hours, EV must be charged to 80% by noon, dishwasher must be finished by 7am, etc.)
  4. A central controller that mixes this all together and activates/controls the different devices

Adding PV systems to the solution increases the complexity by another level, since we would additionally need

  1. Live information about current power consumption
  2. Live information about PV power
  3. Improved controller logic that considers tariff prices in combination with (cheap) PV excess power - with the difficulty, that excess power is limited, so load selection must prioritize and weigh the different loads against each other
  4. Support of batteries as a "negative" load to apply when grid costs are high.

Did I miss anything crucial? Sounds already like quite some endeavor... 😲

@lsiepel
Copy link
Contributor

lsiepel commented Mar 20, 2023

Don't want to oversimpify, but for on a high level, i think such a system should consistent of three modules;

  1. Demand; device x (like a EV) demands to use a powerprofile y (like 5kw for 5 hours) with z constrains (like finishe before 8:00)
  2. Provider; energy providers deliver energy according to a costprofile (like between 8:00 and 10:00 for 1 euro), your own
    PV system can be a energyprovider with a energy profile (like between 10 - 15:00 so much kwh for 0 euro) or a home battery could also be modeled as a energyprovider.
  3. Engine; taking all the demands and providers into calculation according to some user set limits and preferences. (like max concurrent kw/h, timing, look for cheapest or for max self provided or whatever user defined preferences)

Edit:
4. Dashboard/Insights: The system should run fully automated, but i think it should also have an area where it can supply charts / insights. As with most energy related systems this subject deserves its own area/module.

@kaikreuzer
Copy link
Member

This simple demand modelling might work for EVs and heatpumps, but not so well for dishwashers, washing machines and tumble dryers - to schedule them well, you must probably consider the load more fine-grained than as a fixed power value (that's at least what I understand from @jlaur's solution).
For dealing with excess power, I also think that the demand requires some "priority levels" as @mstormi mentioned here with the SG ready modes.
Wrt dashboards: Yes, I agree - it would be nice to have suitable widgets and whole pages for the Main UI that directly support a good energy overview out of the box.

@jlaur
Copy link
Contributor Author

jlaur commented Mar 20, 2023

Let me nonetheless try to summarize what I understood what we would ideally need:

  • A mechanism to store future energy prices (and e.g. also weather forecast data)

Yes, this would come in very handy for these use-cases. I guess we could reboot #844 and the implementation proposal #3000.

This simple demand modelling might work for EVs and heatpumps, but not so well for dishwashers, washing machines and tumble dryers - to schedule them well, you must probably consider the load more fine-grained than as a fixed power value (that's at least what I understand from @jlaur's solution).

Correct, a poor man's solution for not having any PV systems, EV's or heat pumps to play with is to optimize scheduling of the dishwasher during the night. 😄

I also just added another small calculation example for some tumble dryer price feedback: https://community.openhab.org/t/dishwasher-price-calculation-automation/139207/5 - taking advantage of calculations currently implemented in openhab/openhab-addons#14376 - specifically https://github.com/openhab/openhab-addons/blob/e6fbfcf04aaf2fd130601534218a8e1d15825225/bundles/org.openhab.binding.energidataservice/src/main/java/org/openhab/binding/energidataservice/internal/PriceCalculator.java

My initial thought was to have such calculations consolidated in some central place so they could be reused for all bindings providing electricity price information. This could be done by providing an interface that such bindings could implement to deliver the needed data.

You are right this is more fine-grained, but perhaps the calculations would actually be quite similar, if not the same, for EV/heat pump use-cases. One difference might be only having a need for running "full hours", but this seems like a simplification, i.e. rounding. At least I would appreciate to have the fined-grained use-cases included in the design we come up with.

This is of course only a small part in the big puzzle.

@mstormi
Copy link

mstormi commented Mar 20, 2023

It's complex because there's different types of load. Many you can determine (like a dish washing will always take 1.5kWh), some you cannot in neither amount (like a car that constantly charges at say 11 kW but how to do the math if you don't have access to the SoC?) or power requirements (like an inverter heat pump that's consumption will vary a lot).
I sort of solved that in my EM system, but due to those different natures it's not 100% consistent/congruent and still somewhat a compromise.
Working with hour chunks and priority levels corresponding to SGready modes turned out to be an approach that seems to be working well for the time being because it's the 'natural' interface into heat pumps, and can be applied to EV charging as well.
Essentially I set the base level depending on power tariff of the hour but I 'escalate' to a higher level when there's excess PV power. I made the number of hours for levels 1,3 and 4 (2 is "normal") user-configurable, note that's key to applicability.
All, please take another look at my post @kai linked to and the details on the model I laid out.

BTW I'm happy to share what I implemented when it's for a good purpose like here.
Feel free to download the demo of my EMS and extract the scheduling code to see what I did, it's implemented in rules DSL.

On live data from inverters, it's needed yes but don't put it in the mix here that might kill this issue's scope.
Just assume there's (group) items that'll provide values for generation, feedin and consumption.
Same on dashboard. Yes please let's join forces. It's easy to spend helluvalot of time on UI design.
There's a nice widget https://community.openhab.org/t/animated-energy-widget/133510/60 worth starting with.
But it's out of scope for this issue alone here, too.

@jlaur
Copy link
Contributor Author

jlaur commented Mar 20, 2023

To be considered just as a side note: Regarding prices I'll just add that openhab/openhab-addons#14529 has been introduced to avoid redundant VAT calculations. This is probably one of the first "finance" contributions. The next thing that comes to mind could be modelling currencies - currently Number is used for prices without any currency since this is outside the scope of UoM. With the right concept, we could implement currency exchange services. This would be interesting for an ENTSO-E binding since it provides prices only in EUR.

@lsiepel
Copy link
Contributor

lsiepel commented Mar 20, 2023

s power, I also think that the demand requires some "priority levels" as @mstormi mentioned here with the SG ready modes.

I only tried to model the basics, offcourse the powerprofile can be very detailed. Maybe even a minute by minute power usage table for the device. This model won't prevent those details.

In my mind, the model has enough room for something like a home battery or heat pump to get rid of the excess power. Just schedule a 'device' with constraint that it is not allowed to cost more then 0 money and uses x kw/h. But i also see room for priority as a constraint. There should be even more constraints, i didn't meant it as a limited list, just as a model.
The exact details / options / preferences need to be determined, i think it might also be something that iteratevliy may be extended.

The main question is how such feature would fit in OH.
I can see the main scheduling engine that takes all the user preferences / calculations etc into account to be somewhere in core. Maybe the device-that-needs-to-be-scheduled can be something like a Thing in from binding. With some tags you might add some metadata to the Thing so it can be picked up by the scheduling engine. But how would you then model the powerprofile? Provide some json data by a channel? Maybe a bit creative ;-)
The same for energyprovides. You might use a Thing from a binding, add some tags to it and/or require some channels to be present to get it recognized as a 'offical energyprovided' that can be picked up by the core scheduling engine.?

Or do you guys think of some whole new concept?

@kaikreuzer
Copy link
Member

I guess we could reboot #844 and the implementation proposal #3000.

Yes, I was also planning to look a bit closer into that and what it would mean for future prices.

we could implement currency exchange services

Interesting idea, but I would leave it out of scope for the start - this sounds like another complex feature on its own.

BTW I'm happy to share what I implemented when it's for a good purpose like here.
Feel free to download the demo of my EMS and extract the scheduling code to see what I did, it's implemented in rules DSL.

Thanks for the offer, I'll try to have a look. For our controller, I guess we might end up implementing it in Java directly then, but Rule DSLs are then pretty close already.

I only tried to model the basics

Yes, I agree that we should start slowly and cover the basics first - in a way that can be extended later on for more complex cases.

The main question is how such feature would fit in OH.
Or do you guys think of some whole new concept?

Difficult to say. I don't think we will be able to squeeze everything into the existing concepts, so yes, some new kind of construct might be necessary.
I also thought about having it as a feature of a Thing, but that feels as if it is going against the architecture of openHAB as it would prevent providing power profiles for "logical devices", i.e. things that people might only model as items (and have it hooked up to something through HTTP or whatever). I could imagine that we could have something like a "power description", similar to a "state description" for items. We could then have a PowerDescriptionProvider interface and various implementations for this, all delivering the same kind of information that would be used by the PowerController that operates on the items that have such a "power description". Well, this just came as a very first thought, I guess I have to sleep over it - and I am definitely curious of what ideas you come up with!

@masipila
Copy link

@kaikreuzer wrote:

Hey guys, I'm now jumping on this train as well, so count me in! You've all already done amazing work (I'm especially in awe by @masipila rule logics).

Thanks, I appreciate your acknowledgement!

@kaikreuzer wrote

Let me nonetheless try to summarize what I understood what we would ideally need:

1. A mechanism to store future energy prices (and e.g. also weather forecast data)

2. A way to declare load curves for dedicated devices

3. A way to declare and/or calculate future demand of a device (i.e. heating must run 5 hours within the next 12 hours, EV must be charged to 80% by noon, dishwasher must be finished by 7am, etc.)

4. A central controller that mixes this all together and activates/controls the different devices

Adding PV systems to the solution increases the complexity by another level, since we would additionally need

5. Live information about current power consumption

6. Live information about PV power

7. Improved controller logic that considers tariff prices in combination with (cheap) PV excess power - with the difficulty, that excess power is limited, so load selection must prioritize and weigh the different loads against each other

8. Support of batteries as a "negative" load to apply when grid costs are high.

Did I miss anything crucial? Sounds already like quite some endeavor... 😲

@lsiepel wrote:

Don't want to oversimpify, but for on a high level, i think such a system should consistent of three modules;

1. Demand; device x (like a EV) demands to use a powerprofile y (like 5kw for 5 hours) with z constrains (like finishe before 8:00)

2. Provider; energy providers deliver energy according to a costprofile (like between 8:00 and 10:00 for 1 euro), your own
   PV system can be a energyprovider with a energy profile (like between 10 - 15:00 so much kwh for 0 euro) or a home battery could also be modeled as a energyprovider.

3. Engine; taking all the demands and providers into calculation according to some user set limits and preferences. (like max concurrent kw/h, timing, look for cheapest or for max self provided or whatever user defined preferences)

How I see this is as follows:

1. We need a to have a capability to store future price and forecast data
The common nominator between electricity prices and different kinds of forecasts is that the data has timestamps in the future and we need to be able to store them so that we can do calculations based on them.

The common nominator for both the prices and the different forecasts is that they are future-timestamped time-series data, however the forecasted value of timestamp X may change over time as we get closer to it, but for energy optimization calculations the expected result is pretty much always that the fresh value for the same timestamp overwrites the older value for the same time.

I would like to highlight that it's not just a question of electricity prices and temperature forecasts. There are many other forecasts that can be used as an input for energy management optimizations. Solar power production forecast, cloud coverage forecast, wind power production forecast, are the first ones that come to my mind. But as said, these are nothing more than future-timestamped time-series.

2. The price of electricity is a topic of its own
As @jlaur has well explained, the price of electricity consists of many different components. If we think about the European electricity market (read: Nordpool), the spot prices of the energy is just one of the components. The network transfer operator wants their share and these tariffs can be simple or hugely complex.

I recently changed our network transfer contract so that it is no longer a fixed price / kWh like it used to be. Our deal is now that

  • From beginning of April until end of October we pay 4.439 c/kWh of transfer fee and electricity tax. This is easy because it's just a fixed fee which needs to be added on top of the Nordpool spot price.
  • During winter time (beginning of November until end of March) the price is different during daytime and night time. During night time (22-07) the tariff is 4.439 c/kWh but during the day time it's 6.909 c/kWh. The weird thing is that during winter Sundays, the tariff is also 4.439 c/kWh days and nights.
  • @jlaur is in a nice position that in Denmark they can get the prices from an API from Energi Data Service but in Finland I need to do the math by myself on top of the spot prices that I can fetch from an API.

Summa summarum: The electricity price topic has a couple of aspects:

  • Fetching the data from an API
  • Doing some math which may be as simple as multiplying it with a VAT multiplier and dividing by 10 to convert from EUR/MWh to c/kWh or adding a fixed tariff on top of this or it needs conditional logic that "if it's winter Saturday daytime, add this tariff"

3. Calculating the operating mode schedules for different kinds of energy consumers
I just had a conversastion with @mstormi on this topic here: https://community.openhab.org/t/tibber-binding-get-best-price-items-like-awattar-binding/144223/27?u=masipila

I'm intentionally using the word "operating mode" here instead of "ON/OFF schedules" here because @mstormi has a very valid point that the world has shades of gray between the binary ON and OFF. Most ground source heat pumps have a support for SG Ready modes (there are four of them). Some simpler devices like water boilers have just two modes, ON and OFF.

I can easily see that EV charges can have other operating modes than just ON and OFF, they could for example provide an interface to allow changing the current (e.g. 8A, 10A, 13A, 16A, 32A).

Anyway, we would ideally find a concept here which is simple for users but flexible enough for different kinds of use cases. @mstormi approached this slightly differently in his solution than I did in mine, see the discussion in the link above.

But anyway, to not go into the solution yet, I'll try to write a couple of use cases in a user story format.

a) As an owner of an electric vehicle, I want to find the best time to charge the vehicle between 21 this evening and 06 tomorrow so that it will be ready in the morning. I know that I need to charge the car for X1 hours. I do not want to interrupt the charging. In other words, the X1 hours must be consecutive.

b) As an owner of a water boiler, I want to to find the best time to heat the domestic hot water tomorrow. I know that I need to heat the water for X2 hours. I do not want to interrupt the heating because stopping and re-starting it would mix the water layers. In other words, the X2 hours must be consecutive.

c) As an owner of an air-to-air heat pump, I want to optimize the heating of the house by changing between two operating modes depending on the price of electricity. Based on the weather forecast, I know that I need to have mode A enabled for X3 hours of the day and I want these to be the cheapest hours of the day. The rest of the day (all other hours) I can use mode B.

d) As an owner of a ground source heat pump that supports SG Ready modes, I want to toggle mode 4 when the price of the electricity is below a configured threshold.

(there are of course more user stories than these, but this should be a good start)

All this would fall into the "engine" category that @lsiepel was suggesting above.

@mstormi
Copy link

mstormi commented Mar 22, 2023

Some more input on levels. I also integrated EVCC Electric Vehicle Charge Controller in my EM system.
They're also discussing charge modes along these lines in their project. Their current implementation is actually 4 modes:

  • off
  • only pv surplus (with on/off if below the minimum charge power which is 6A/1.4kW per phase)
  • pv surplus but no on/off i.e. constant with a minimum of 1.4/4.2kW 1/3 phases
  • max

FWIW, EV charging is pretty similar in terms of black-white-gray coloring @masipila mentioned.
Some EV chargers ("wallbox" in DE) can only do on and off, but most provide a number of fixed levels (usually integer values of the amperage). Sometimes (like in Teslas) it not the charger but the car itself you need to talk to.

These EVCC modes I felt match SGr modes quite well and since I had an existing SGr implementation for heat pumps in my EMS, I just did the mapping for EVs, too.

@lsiepel
Copy link
Contributor

lsiepel commented Mar 22, 2023

e more input on levels. I also integrated EVCC Electric Vehicle Charge Controller in my EM system. They're also discussing charge modes along these lines in their project. Their current implementation is actually 4 modes:

  • off

From a user perspective i can understand all the cases. With those cases you demonstrated that it can get really complex and without proper design this will turn into spaghetti. As allways, but specifically in this case proper seperation of concern is very important here.

As every EnergyProvider (just to be sure, this can be an external company, a battery, owned solar panels etc) knows what parameters are important (sun, cloud, windspeed, grid state, battery-wear or whatever you can think off) for it to make good prognoses for available power levels and prices it is best to keep all those details under the responsibility of this EnergyProvider. I would suggest to keep the interface between this EnergyProvider and the SchedulingEngine as simple as possible. Possibly not much more than a list of some generic propertys and a list of datapoints holding timestamp, available power, cost of power.

The same for EnergyUser / Device it knows best for itself how to calculate the PowerProfile and the interface could also be simple as: some generic properties/ constrains and the PowerProfile (i see that as a list of data points for example seconds after start, power usage)

The scheduling engine can be very lean as all the hard parts have allready been done.

I would really not suggest to make the engine responsible for determining the prices of the energy provider as that will need an extended and ever changing interface between the energyprovider and the engine.

Anyway, the above is just a suggestion, and there is one step before this and that is how all this will be tied into the openHAB achitecture.

  • re-use items in some kind of group with metadata to construct a EnergyUser / EnergyProvider? Very flexible and homekit and other systems use this method allready, but how to add the additional powerprofile and specific data?
  • create a new type addon ?
  • allow current addons to annotate things/channels to construct a EnergyUser / EnergyProvider in a more controlled pre-set way?

@masipila
Copy link

@lsiepel can you please elaborate your thinking of the PowerProfile? For what purpose do we need it?

Not challenging, just trying to follow your thought process.

@masipila
Copy link

Regarding the considerations of EnergyUser and the existing openHAB concepts. In my eyes all these EnergyUser devices are Things. There are Bindings to most of these already and eventually Items will abstract the state changes from one mode another (like ON / OFF or from SG Ready mode 1 to 4).

The only thing that comes to my mind is that some use cases might need to know how much power the device will consume (and from which phase or all of them) if there would be some sort of a load balancing use case where you can't toggle all the devices on at the same time. Is this what you mean with the powerProfile and can you provide an example use case or user story to demonstrate the intended usage that you have in your mind?

@lsiepel
Copy link
Contributor

lsiepel commented Mar 23, 2023

Regarding the considerations of EnergyUser and the existing openHAB concepts. In my eyes all these EnergyUser devices are Things. There are Bindings to most of these already and eventually Items will abstract the state changes from one mode another (like ON / OFF or from SG Ready mode 1 to 4).

The only thing that comes to my mind is that some use cases might need to know how much power the device will consume (and from which phase or all of them) if there would be some sort of a load balancing use case where you can't toggle all the devices on at the same time. Is this what you mean with the powerProfile and can you provide an example use case or user story to demonstrate the intended usage that you have in your mind?

Yes, i meant the PowerProfile as a way of describing the required load usage over time. And +1 for the support of not only on/off but also different levels. Every level should have its own PowerProfile i guess.

@kaikreuzer
Copy link
Member

Just to make sure that I follow correctly:

Yes, we could have many bindings that each bring their own EnergyProvider and which have a channel through which they provide future energy prices to a linked item. Such bindings would have to deal with VAT, currencies, etc. on their own, though.

So I would really like to see how the user could have the divide by ten

Maybe we could additionally have a generic GridEnergyProvider for the "standard" cases, which takes a "future prices" items as a configuration and which offers additional features such as adding VAT, converting from EUR to ct or adding another channel for fixed costs/taxes into the calculation.

can we please call this as timeResolution instead of 'granularity'?

Sure thing.

@J-N-K
Copy link
Member

J-N-K commented Mar 25, 2023

I would be willing to look into the currency issue, there is already #3408 for that. I would like to hear some comments if we should try to fit it into UoM or create a new type for that.

Another thing (which is probably not so prominent like electricity): there may also be dynamic water or gas tariffs that should be included and a consumer could use more than one of them (e.g. dish washer).

@kaikreuzer
Copy link
Member

Thanks @J-N-K. My first impuls is that it should be fitted into UoM, but I haven't thought through the consequences (mainly wrt dynamic exchange rates).

a consumer could use more than one of them (e.g. dish washer).

That's true, but are there really any countries in the world where there are dynamic tariffs for water? I think adding such a feature would heavily increase complexity as the search for optima would have to be done for different dimensions simultaneously - I'd rather prefer to stay away from this (for now).

@J-N-K
Copy link
Member

J-N-K commented Mar 26, 2023

I had a quick look and I think we have to extend AbstractQuantity to a new MoneyQuantity. We could then implement.toUnit to use a CurrencyConversionProvider. It's not super easy, but I think it's doable. The benefit is that we don't need a new data type for that and can easily do any calculations we want, even besides this topic (e.g. calculate the cost of garden watering based on consumption.

I'm not aware of any country that does it. I would not implement that in the first step, just if it's possible to keep it extendable then we should do it. We might see gas tariffs in the future that at least have daily or monthly changes (especially thinking of hydrogen replacing fossil gas).

@J-N-K J-N-K pinned this issue Mar 28, 2023
@jlaur
Copy link
Contributor Author

jlaur commented Mar 29, 2023

In the openhab/openhab-addons#14376 I decided to provide the elements individually

Just to be clear, in lack of a better word, with (price) "elements" I mean the components that make up the total price you have to pay per kWh. In my case this is spot price, net tariff, system tariff, electricity tax and transmission net tariff. On top of that the fee to my electricity company, which is luckily fixed (no binding for that 🙂).

This is fine. If the hourly-prices would then be replaced by a Number channel where the prices are written to with a future timestamp (with #3000), this could be easily used for charts and also be consumed by an GridEnergyProvider - if we manage to implement this class in a configurable and generic way, we could possibly add this as a default implementation to the core directly.

👍

one binding could provide the spot price and another one the relevant tariffs for a specific grid company or area.

Yes, absolutely - that could all be configuration options for this provider.

So, as an example - two of my price components (let's try that word now) are dynamic: Spot price and net tariff.

Currently both are provided by Energi Data Service, but let's say I wanted to use another binding (or a rule, script calling the REST API, karaf command etc.) for getting the spot price. I would now have at least two different price components (items) from different sources that should be taken into consideration when performing calculations, as the cheapest period has to be calculated from the sum.

Maybe you already had this in mind, so just to be sure and fully aligned. The user should be able to configure which items to include in the calculations.

@masipila
Copy link

masipila commented Apr 1, 2023

@jlaur that's clear to me. For me, I can't get the grid tariff and the spot price from the same datasource, but that should not be an issue. I could have two separate Bindings, on which fetches the spot prices from Entso-E and another that calculates the grid tariffs and electricity tax.

According to this [1], if the user places the different items in the same group and persists the group, then the sum of all items in that group will be persisted and we have the total price. But doing the summing should not be difficult even if it didn't happen automagically by persisting the group.

If @kaikreuzer 's proposed class diagram is OK for everyone, should we break this thing into separate issues and establish a backlog of them?

  1. One issue would be to get the Binding needs to be able to persist data with future timestamps, and I believe @kaikreuzer was in favor of covering this in the scope of Enable binding to store historic states #3000

  2. If we start by developing a capability to fetch and store the prices, we would next need EnergyManagementParticipantRegistry, EnergyManagementParticipantProvider,
    EnergyManagementParticipant and EnergyProvider

  3. Once we have 1 and 2, we should be able to create the first Bindings for different price data sources, for example Entso-E, the Danish EnergiDataService and so on.

  4. We could then proceed to EnergyConsumer and PowerProfile

Does this sound like a plan?

[1] https://community.openhab.org/t/energy-rules-sum-of-group-to-item-help/10264/5

@lsiepel
Copy link
Contributor

lsiepel commented Apr 1, 2023

@jlaur that's clear to me. For me, I can't get the grid tariff and the spot price from the same datasource, but that should not be an issue. I could have two separate Bindings, on which fetches the spot prices from Entso-E and another that calculates the grid tariffs and electricity tax.

According to this [1], if the user places the different items in the same group and persists the group, then the sum of all items in that group will be persisted and we have the total price. But doing the summing should not be difficult even if it didn't happen automagically by persisting the group.

If @kaikreuzer 's proposed class diagram is OK for everyone, should we break this thing into separate issues and establish a backlog of them?

  1. One issue would be to get the Binding needs to be able to persist data with future timestamps, and I believe @kaikreuzer was in favor of covering this in the scope of Enable binding to store historic states #3000
  2. If we start by developing a capability to fetch and store the prices, we would next need EnergyManagementParticipantRegistry, EnergyManagementParticipantProvider,
    EnergyManagementParticipant and EnergyProvider
  3. Once we have 1 and 2, we should be able to create the first Bindings for different price data sources, for example Entso-E, the Danish EnergiDataService and so on.
  4. We could then proceed to EnergyConsumer and PowerProfile

Does this sound like a plan?

[1] https://community.openhab.org/t/energy-rules-sum-of-group-to-item-help/10264/5

With persisting, do you mean storing it in some database? As i don't see that as a requirement, the EnergyManagementService could keep data in memory.

Anyway, i see some kind of gap between the proposed items (openHAB architecture) and the data structure (requirements), but maybe that is a limitation of my head :-)
Atleeast future prices and the powerprofile consist of many datapoints depending on how far to look ahead and the time resolution. These two datatypes may consist of 100+ datapoints each. How would these items be structured in a maintainable and understandable way for end-users?

I would have hoped that the framework could take care direct communcation in the background between the EnergyProvider, EnergyConsumer and the EnergyManagement service.

@kaikreuzer
Copy link
Member

The user should be able to configure which items to include in the calculations.

@jlaur Yes, agreed.

Does this sound like a plan?

@masipila Yes, sounds good to me.
For (1), I have just commented on #3000.
For (2), I'll try to come up with a suggestion / draft PR soon®.

I would have hoped that the framework could take care direct communcation in the background between the EnergyProvider, EnergyConsumer and the EnergyManagement service.

@lsiepel Yes, this would be exactly my plan as well - there can only be specific EnergyProviders that can consume persisted future item states (i.e. future prices) from items as well. PowerProfiles will rather be always provided through a direct interface to the EMS.

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/bringing-electricity-information-from-eloverblik-dk-and-energidataservice-dk-into-openhab/143470/24

@kaikreuzer
Copy link
Member

Hey guys, I just want to say that I am still alive and haven't forgotten about this topic. I'll probably not be able to make big advancements before the OH4 release end of June, but it is definitely my absolutely top priority right after that.

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/searching-for-willing-to-create-a-general-energy-control-binding-add-on/149165/4

@wborn
Copy link
Member

wborn commented Aug 29, 2023

It would also be nice if the solution would be a bit more generic. For instance you might also want to have something for redistributing rain water, money, heat, cold etc. one day. 🙂 I.e. resource management.

@subbamaggus
Copy link

hi,

i went through the whole issue here.
is there already a start in the core? is it possible to start it as add on?

one thing i would like to add here:
the feature here is mostly talking about planning the future. how about a judgement for the moment?
the simplest one could be "i have more power than i need, store it". for this there is no need for storing a forecast on price or weather or sth more. sure that should be added later.... but first things first, right?

i will checkout the main branch and see if i could find some work done on this.

sounds like fun!!!

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/energi-data-service-binding-4-0-0-0-4-1-0-0/144370/38

@andrewfg
Copy link
Contributor

I think somebody is already working on a UoM for converting money amounts i.e USD per Euro (say). And (part of) your discussion is very similar to that -- namely kWh per Euro (say) which you might convert via UoM to Joule per DKr (say). Both these would be extensions of UoM where the conversion factors are variable rather than fixed in code. The variable rates are a time series where past rates are historical actual values, and future rates are forecasts. The source of these rates might be e.g. Bank of Denmark (say) or EON (say), or in my latter example (with double UoM conversion) both sources (say). The intervals between two fixed rate UoM conversion data points could be subject to various interpolation algorithms (e.g. linear, or keep last value, ..)

@openhab-bot
Copy link
Collaborator

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/best-approach-for-energy-consumption-usage-queries/151393/21

@mstormi
Copy link

mstormi commented Feb 26, 2024

Now with OH4(.1) out and Number:Currency and Number:EnergyPrice implemented, shouldn't we be picking this up again ?

I just applied for a grid discount according to German §14a EnWG and my provider responded the industry is currently thinking to implement EEBus as a control protocol to power-dim or shutoff large consumers. It's still under evaluation, just spreading the word. They've also sent me a spec from the VDE if someone is interested (but that's fairly useless).

Either way, I believe openHAB would benefit from an EEBus implementation.
Anyone willing to take on the challenge ?

@florian-h05
Copy link
Contributor

There is a community developed EEBus binding: https://github.com/csowada/openhab-ebus-binding.
Probably it should be attempted to make it a official one.

@splatch
Copy link
Contributor

splatch commented Feb 26, 2024

@florian-h05 Binding you refer to is ebus, while Markus talks about eebus (https://www.eebus.org/). I know, its quite confusing, but later is more recent and (in theory) spans across more areas than just heating/ventilation.

@florian-h05
Copy link
Contributor

Oh thanks for the hint, seems like it also confused me ;-)

@mstormi
Copy link

mstormi commented Feb 26, 2024

For what's it worth, EVCC has a working EEBus implementation in Go and is now working on v2.

On forecasting, what about finalizing openhab/openhab-addons#13308 for 4.2.
@jlaur @weymann what's missing ?

@jlaur
Copy link
Contributor Author

jlaur commented Feb 26, 2024

On forecasting, what about finalizing openhab/openhab-addons#13308 for 4.2.
@jlaur @weymann what's missing ?

The current status can be seen in the PR - last comment.

@DerAndereAndi
Copy link

I would like to make some comments about EEBUS:

  • ebus and EEBUS are two completely different things, they have nothing in common
  • the evcc project uses the EEBUS implementation of https://github.com/enbility/ , which I am developing. It consists of 4 repositories fully under MIT license and is a major task to implement. I am working on them since 2 years and had developed a prototypical version over 2 years before that. It is impossible to implement it within a few months or weeks. It is way too complex.
  • The CEMd repository's goal is to provide a a simple API so EEBUS can be used with only little knowledge about the protocol itself. One could create a service on top of it which then e.g. could use a websocket interface to other systems like OpenHab which are not based on Go.
  • During the last year I am improving an refactoring the repositories a lot and target a 0.5 release in the near future. This is what evcc is calling V2.

Integration would still be a big task, as the service on top of CEMd would have to be written in Go and an interface would have to be defined. Once that is done, support for germans §14a technically could also be implemented. Feel free to get in touch, my contact details are available at https://enbility.net

@florian-h05
Copy link
Contributor

I guess a different option would be to write a JNI wrapper for your EEBus implementation.

I have googled a bit, and I also found the Java EEBus implementation from openMUC, which is created by a team of the Fraunhofer ISE in Freiburg, Germany: https://www.openmuc.org/eebus/

@DerAndereAndi
Copy link

@florian-h05 sadly it is not open source and I haven’t seen it working with a device yet. But maybe they would be interested anyway helping you to have a show case

@kaikreuzer
Copy link
Member

I guess I have to face the truth of my situation that I won't be able to find the time to work on that topic the way I intended. Since I spent some time and proposed a potential architecture for tackling the problem, exactly one year has passed without any progress on my end - I'm feeling very sorry about that. 😢

So please do not wait for me here - if anybody is interested to pick up this topic, please speak up and drive it forward!
Wrt the EEBus discussion: As @DerAndereAndi rightly says, I don't see a native EEBus implementation in openHAB feasible; I am not even convinced that a proper EEBus implementation is possible in the long-run, since my impression/experience is that this is a very commercially-focussed initiative that rather tries to keep control and which makes it hard for open-source to get a grip on it.

In any case, I would split the discussion about general energy management (this issue) and EEBus. Imho, if we are able to create a modular architecture like the one suggested above, EEBus could possibly be one implementation behind the interfaces, but it would leave the room for many other (simpler) approaches as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An enhancement or new feature of the Core
Projects
None yet
Development

No branches or pull requests