Remote openHAB Binding and Solarwatt SMF

I used this Binding to access the openHAB instance on the “Solarwatt Manager Flex (SMF)” for some years.

Since an update of SMF 2 or 3 days ago the Binding cannot longer connect to the SMF-openHAB because the signon suddenly does not only need a password, it now also needs a sessionid stored in a cookie! And this sessionid is only 30 Minutes valid.

As the Solarwatt Binding is unusable for SMF and only the Remote OH can be used I cannot retrieve data in my openHAB any more! (I use 4.3.5 and tested it also under 5.0.2 openHABian).

Any ideas how this new sessionId could be integrated?

I’m a little confused with how the Remote openHAB binding lets you do anything beyond connecting two openHAB instances.

It’s also not clear if you’re problem is worth the Remote openHAB building or some other binding.

As far as I know, there’s been no changes to the Remote openHAB binding since before OH 4.3.

It is definetely not an error or problem of Remote openHAB Binding! This side worked and works as designed.

The difficulty has been braught in some days ago from the other side: Solarwatt/Kiwigrid with their SMF, based on openHAB. They invented besides the password, for whatever reason, a sessioncookie and since then the acess from my Remote openHAB Binding to the SMF’s openHAB doesn’t work any more.

The SMF is a device installed in my house to control my photovoltaic installation. (more or less openHAB on a Raspi with some additional interfaces).

The problem has also been detected and discussed in the HA-Forum i. e. here and here

To my understanding they created at HA a workaround to catch the “kiwisessionid” out of the cookie to be able to connect to the /rest/api of SMF-openHAB.

My question is, whether something like that could also be integrated in openHAB as script or somewhere else. And I really need help to solve this issue.

That’s pretty cool! I wasn’t aware that anyone was using OH like that.

Possibly but you’ll need to abandon the Remote OH add-on and do the HTTP REST calls to the SMF directly using a rule or an external script.

Or, if you can access the openHAB on the SMF and change things, you might be able to use the MQTT Event Bus rule template to link the two OH instances in another way which will bypass what ever additional authentication they implemented.

I hope they support openHAB as a sponsor…

But I think even then I’d need the kiwisessionid, or?

2,5 years ago that was possible. But after some versions of their SMF they hided it and I still cannot find it (port I think)… Remote OH was such a perfect solution! It was read only and so noone could compromise their local openHAB instance…

THEY ARE SO STUPID TO LOCK THIS POSSIBILITY!

I’m not sure how we would know. Maybe they donate to the foundation. Ideally, submitting PRs would be the best way they could contribute.

Yes, you’d have to implement the HTTP calls as necessary.

All the Remote openHAB add-on does is make HTTP calls to the other OH’s REST API. You’d have to do the same, only with the addition of acquiring and using the cookie authentication.

If Remote openHAB can do it the port is there and open. I assume you discovered the Remote openHAB Thing instead of manually configuring it. So you should be able to find the port number on that Thing.

But you’ll also need the credentials to log in as an admin role which is likely not available.

Yesterday I made a portscan with nmap and saw, that there are only 2 ports open: 80 ant 443. So I think, they implemented a kind of redirection from openhab paperUI to their own local SMF app.

Then Remote openHAB add-on wouldn’t be able to connect at all except through one of those two ports and what ever reverse proxy they’ve implemented is allowing access to the OH REST API. All of that can be confirmed by looking at the Remote openHAB Thing in your instance of OH.

And if that’s the case you should be able to bring up MainUI with https://<ip of SMF>/overview and you might be able to bring up the REST API explorer with https://<ip of SMF>/developer/api-explorer. If not, they’ve locked it down and made it so you cannot access their insdtance of OH at all except through their system.

Hi together,

I am completely new to the whole topic and to openHAB. I installed it just today to find a possibillity to access the data of my solarwatt PV installation where a SMF is part of.

I also tried to connect via the Remote openHAB Binding, an of course I failed.

The two URLs suggested by @rlkoshak boeth lead to the same UI as just http://<ip of SMF> :frowning:

The only thing that leads to something else is http://<ip of SMF>/rest/

Unfortunatelly I am way to unexperienced to know how I could integrate these information (especially the ones in “items”) into openHAB.

Does anybody have an idea about that? Just integrating the information out of the JSON structure via HTTP request or something like that?

Thanks in advande and
best regards
Jens

as Jens also said: all those links are redirected to the SMF signon page.

:person_shrugging: Solarwatt has closed off their instance of OH. You’ll have to access it through their reverse proxy and the Remote openHAB add-on will no longer work.

I am axperimenting with a http binding … also with experience level “0”. Maybe this leads to a way to access the values. Nevertheless there are still 152 values available in /rest/items

Update: I have not been successfull yet. All I get back when trying to read a JSON element is

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="/kiwios-components/styles.css"></link> <style> .card { padding: 30px; margin: 90px auto 0; width: 80%; max-width: 550px; box-shadow: 0 0 4px #888; background: white; } @media screen and (max-width: 600px) { .submit-button { width: 100%; } } </style> </head> <body> <kiwios-app-frame> <kiwios-app-bar></kiwios-app-bar> <kiwios-app-content> <div class="card"> <div class="row"> <div class="col-xs-12 col-sm-6 col-md-4"> <form method="POST" action="/auth/login"> <h3 class="primary-color">Sign In</h3> <input value="installer" name="username" type="hidden" /> <input value="/" name="url" type="hidden" /> <div> <div class="mco-mat-input"> <input class="highlighted" name="password" type="password" required /> <span class="highlight"></span> <span class="bar"></span> <label>Please enter the gateway password</label> </div> </div> <div class="mt-3 d-flex"> <input class="mco-mat-raised-btn submit-button" name="submit" type="submit" value="Login" /> </div> </form> </div> </div> </div> </kiwios-app-content> <kiwios-app-footer cookie-settings></kiwios-app-footer> </kiwios-app-frame> <script src="/kiwios-components/app-frame.js"></script> </body> </html> 

But according to what I read here and in the links there, this seems to be a problem to a lot of users.

… only after you signed on to SMF locally and then only for around 30 minutes…

Unfortunatelly that’s right :frowning:

Does anybody know, how this could be automized within a cycle > 30 min?

Update: Eventually I was able to solve the problem using the proxy script and the step by step manual from here

Hi Gerd and @BlueJens , thanks so much for collecting the infos you shared in this thread. I’m aware you did it for different reasons than the ones that got me here, but I’m still super happy. Up until a few days ago I had no idea that the kiwigrid device is based on a version of openHAB.

I’m absolutely new to openHAB, therefore the concepts and naming conventions are as well. What I did want to ask you: I’m currently using the data provided by the endpoints under /rest/items/ to feed into HA as sensor values. That works smoothly (since fixing the annoying authentication issue that came up recently). What I cannot do with that yet is actually control the underlying devices. Concrete example: the SMF also controls a wallbox, and at the moment the charging mode (off, on, only when enough solar power available) and the maximum charging power can only be controlled via the cloud-based app of the pv provider.
What would be a good next step to look into for trying to find out if there is an option to control the wallbox locally?

This is the example resonse for a wallbox-related endpoint, the “readonly: false” part sounds as if there would be an option to also change settings via REST. Would that have to happen via a POST request to the “items” endpoints, or would that work via a “bindings” endpoints? (I didn’t have the chance yet to check if the “bindings” endpoints are available or blocked though)

link “``http://karaf/rest/items/foxessevcharger_wallbox_xxxxxxxxxxxxxx_switchable_switchThing_P_active”
state “0 W”
stateDescription
pattern “%.2f %unit%”
readOnly false
options
editable true
type “Number:Power”
name “foxessevcharger_wallbox_xxxxxxxxxxxxxx_switchable_switchThing_P_active”
label “#max_charging_power”
tags
0 “emiaas_resolver”
groupNames

If this is way too much highjacking of this thread, please let me know. One way or another: thanks in advance for your help! :slight_smile:

Cheers!

So you really want to implement an own logic for the socalled “PV-Überschussladen”?! I understand your stomach aches regarding Kiwigrid’s implemantation and especially that they want to implement “more and more AI” into this makes me also nervous. My installation is 3 years old and includes a Webasto Loader. For about 6 months of this time SMF did not correctly control the Loader. Sometimes I had to unplug the Webasto from the network to be able to load my car… With my experiences today with SOLARWATT/KIWIGRID I never ever would buy this again! But … too late.

Now to your question: In my opinion you first have to decouple your charger completely from SMF. Then you have to find out the commands to control the Charger (via a TCP 502 / Modbus binding?) and finally you have to build your own rules to control “PV-Überschussladen”.

Do you really want to do this?

“Want” is not really the right wording here to be honest :wink: At this point in time it’s mostly driven by 2 reasons:

  • EKD (who installed the kiwigrid box) doesn’t look like a very stable company to me (from people’s experiences, and recent news around layoffs etc). If they close, I’m suspecting that kiwi will not get payed for their whitelabled cloud services anymore, and might eventually stop providing the service. Anything that is exclusively possible via app would then stop working. So I’d like to understand alternatives “just in case"
  • The car charged by the wallbox only allows limiting the maximum battery charge (100%, 90%, 80%, …) when using the payed subscription of the car company. So I wanted to look into the option to combine the current charge level (as a sensor value) with a “kill switch" for the wallbox.

I actually posted here not because I want to implent that in openHAB, but because I was hoping that with openHAB being the base for the kiwibox, there might be “best practices" on where to look further when it’s about controlling connected hardware via openHAB :slight_smile:

This issue is still open. At the moment I try to work with the modbus binding. Some success for my inverter - but no chance for Battery and Wallbox (Battery: No Modbus documentation, WEBASTO NEXT: Connects but polling doesn’t work!)

So - are there any (new) ideas how to connect to the SMF unit (using openHAB remote binding or whatever and including the neccessary session cookie(s))?

I’m thinking to move to Home Assistant because they seem to have solved the problem - but that would be a big step for me after all those years using openHAB!

So… I think I have too many gaps in my knowledge about JS and openHAB :frowning:

Maybe someone can help me with the script?

  • JS addon installed
  • Remote Openhab Binding installed
  • Something missing?

The script has been adderd as a rule, running every 15 Minutes.

The error I see in openhab.log is

2026-02-11 17:55:45.820 [ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'SMF-get-sessionid' failed: TypeError: undefined has no such function "_getTriggeredData" in <eval> at line number 2 at column number 70

The script I try to use ist from here: photovoltaik forum

Here ist he code I use:

var { rules, triggers, items, things } = require('openhab');
var logger = log('solarwatt-cookie');

var HttpClient = Java.type('java.net.http.HttpClient');
var HttpRequest = Java.type('java.net.http.HttpRequest');
var HttpResponse = Java.type('java.net.http.HttpResponse');
var URI = Java.type('java.net.URI');
var CookieManager = Java.type('java.net.CookieManager');
var CookiePolicy = Java.type('java.net.CookiePolicy');
var BodyPublishers = Java.type('java.net.http.HttpRequest.BodyPublishers');
var Duration = Java.type('java.time.Duration');

// === KONFIG ===
var OH_TOKEN = 'oh.xxx.xxx'; 
var baseURL = 'http://192.168.178.nnn'; // Solarwatt Manager Flex
var username = 'installer';
var password = 'xxx';
var ohRest = 'http://localhost:8080'; // openHAB-REST (im Docker: HTTP lokal)
var thingUID = 'http:url:solarwattFlex'; // remoteopenhab:server:SMF-Remote ??
var SESSION_TTL_SEC = 900; // 15 min
var RENEW_EARLY_SEC = 60; // 60s vor Ablauf bereits erneuern
// ============

// Hilfsfunktionen
function nowSec() { return Math.floor(Date.now()/1000); }

function readExpires() {
try {
var s = String(items.getItem('Solarwatt_SessionExpires').state || '0');
var n = parseInt(s, 10);
if (isNaN(n)) return 0;
return n;
} catch(e) { return 0; }
}

function shouldRenew(force) {
if (force) return true;
var exp = readExpires();
return nowSec() >= (exp - RENEW_EARLY_SEC);
}

function buildClient(cookieManager) {
return HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(6))
.followRedirects(HttpClient.Redirect.NORMAL)
.cookieHandler(cookieManager)
.build();
}

function loginAndUpdate(force) {
if (!shouldRenew(force)) {
logger.info('Session noch gültig – kein Re-Login nötig.');
return;
}

var cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
var client = buildClient(cookieManager);

// === STEP 1: Login ===
var postData =
'username=' + encodeURIComponent(username) +
'&password=' + encodeURIComponent(password) +
'&url=/';

var reqLogin = HttpRequest.newBuilder()
.uri(URI.create(baseURL + '/auth/login'))
.header('Content-Type', 'application/x-www-form-urlencoded')
.POST(BodyPublishers.ofString(postData))
.build();

var resLogin = client.send(reqLogin, HttpResponse.BodyHandlers.ofString());
if (resLogin.statusCode() >= 300)
throw 'Login failed (' + resLogin.statusCode() + ')';

// === STEP 2: Session aktivieren ===
client.send(
HttpRequest.newBuilder().uri(URI.create(baseURL + '/rest/items')).GET().build(),
HttpResponse.BodyHandlers.ofString()
);

// === STEP 3: Cookie auslesen ===
var cookies = cookieManager.getCookieStore().getCookies();
var cookieValue = null;
cookies.forEach(function(c){ if (c.getName() === 'kiwisessionid') cookieValue = c.getValue(); });

if (!cookieValue) throw 'kiwisessionid not found';
logger.info('kiwisessionid refreshed: ' + cookieValue);

items.getItem('Solarwatt_SessionCookie').postUpdate(cookieValue);
items.getItem('Solarwatt_SessionExpires').postUpdate(nowSec() + SESSION_TTL_SEC);

// === STEP 4: Thing-Config holen ? Cookie-Header setzen ? config PUT ===
// 4.1 GET /rest/things/{uid}
var reqGetThing = HttpRequest.newBuilder()
.uri(URI.create(ohRest + '/rest/things/' + encodeURIComponent(thingUID)))
.header('Authorization', 'Bearer ' + OH_TOKEN)
.header('Accept', 'application/json')
.GET()
.build();

var resGetThing = client.send(reqGetThing, HttpResponse.BodyHandlers.ofString());
if (resGetThing.statusCode() >= 300) {
throw 'Cannot GET thing (' + resGetThing.statusCode() + '): ' + resGetThing.body();
}

var thingObj = JSON.parse(String(resGetThing.body()));
var cfg = thingObj.configuration || {};

// Header setzen (String oder Array – beides unterstützen)
if (Array.isArray(cfg.headers)) {
cfg.headers = ['Cookie=kiwisessionid=' + cookieValue];
} else {
cfg.headers = 'Cookie=kiwisessionid=' + cookieValue;
}

// 4.2 PUT /rest/things/{uid}/config (nur configuration-Map!)
var reqPutCfg = HttpRequest.newBuilder()
.uri(URI.create(ohRest + '/rest/things/' + encodeURIComponent(thingUID) + '/config'))
.header('Content-Type', 'application/json')
.header('Authorization', 'Bearer ' + OH_TOKEN)
.PUT(BodyPublishers.ofString(JSON.stringify(cfg)))
.build();

var resPutCfg = client.send(reqPutCfg, HttpResponse.BodyHandlers.ofString());
if (resPutCfg.statusCode() >= 300) {
throw 'PUT failed (' + resPutCfg.statusCode() + '): ' + resPutCfg.body();
}
logger.info('Thing config updated with new kiwisessionid.');

// === STEP 5: Thing reinit ===
var t = things.getThing(thingUID);
t.setEnabled(false);
Java.type('java.lang.Thread').sleep(500);
t.setEnabled(true);
logger.info('Thing restarted.');
}

// === Regeln ===
// 1) Zeitgesteuert alle 10 Minuten (mit Ablaufprüfung)
rules.JSRule({
name: 'Solarwatt Session Login (cron)',
triggers: [triggers.GenericCronTrigger('0 0/10 * * * ?')],
execute: function(){ try { loginAndUpdate(false); } catch(e){ logger.error('Solarwatt login error: ' + e); } }
});

// 2) Manueller Button: ON = sofort erneuern (force), danach Button wieder auf OFF
rules.JSRule({
name: 'Solarwatt Session Login (manual)',
triggers: [triggers.ItemCommandTrigger('Solarwatt_SessionRefresh', 'ON')],
execute: function() {
try {
loginAndUpdate(true);
} catch(e) {
logger.error('Solarwatt login error (manual): ' + e);
} finally {
// Button zurücksetzen
try { items.getItem('Solarwatt_SessionRefresh').postUpdate('OFF'); } catch(_){}
}
}
});