Great news to see that someone is working on this. Do you mind sharing your version of the script?Cossy wrote:I did make a simple adjustment by changing the call back url to the following:
redirect_uri = "https://www.marshflattsfarm.org.uk/nibe ... /index.php" # Don't alter this or anything else!
Based on the blog post of: https://www.marshflattsfarm.org.uk/word ... ge_id=3480 which did the trick for me and it now working for multiple hours.
Tempting to do a cleanup later as well, anybody else still working on this code?
Domoticz RPC for NIBE Uplink
Moderator: leecollings
Re: Domoticz RPC for NIBE Uplink
-
- Posts: 32
- Joined: Tuesday 28 August 2018 15:36
- Target OS: Linux
- Domoticz version: 2021/1
- Location: Germany
- Contact:
Re: Domoticz RPC for NIBE Uplink
Working fine for me 
Please ensure that you change your redirect url at the Nibe api webpage in https://www.marshflattsfarm.org.uk/nibe ... h2callback

Please ensure that you change your redirect url at the Nibe api webpage in https://www.marshflattsfarm.org.uk/nibe ... h2callback
Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This software has been designed to work with Nibe Uplink API https://api.nibeuplink.com/Home/About
# It's aimed for Domoticz running on Raspberry Pi
#
# This software licensed under the GNU General Public License v3.0
import json
import os
import plistlib
import requests
from urllib import urlencode
import sys, getopt
from datetime import datetime
import time
import logging
# Global (module) namespace variables
redirect_uri = "https://www.marshflattsfarm.org.uk/nibeuplink/oauth2callback" # Don't alter this or anything else!
baseEndPointUrl = 'https://api.nibeuplink.com'
authorizeEndpointUrl = baseEndPointUrl + '/oauth/authorize'
tokenEndpointUrl = baseEndPointUrl + '/oauth/token'
cfgFile = sys.path[0] + '/config.json'
configChanged = False
newDevicesList = [] # This is a python list
PROGRAMNAME = 'Domoticz RPC for NIBE Uplink'
VERSION = '2.0.0'
MSG_ERROR = 'Error'
MSG_INFO = 'Info'
MSG_EXEC = 'Exec info'
tty = True if os.isatty(sys.stdin.fileno()) else False
isDebug = False
isVerbose = False
def query_yes_no(question, default="no"):
"""
Ask a yes/no question via raw_input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is True for "yes" or False for "no".
"""
valid = {"yes": True, "y": True, "ye": True,
"no": False, "n": False}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
sys.stdout.write(question + prompt)
choice = raw_input().lower()
if default is not None and choice == '':
return valid[default]
elif choice in valid:
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n")
def connected_to_internet(url='http://www.google.com/', timeout=5):
try:
_ = requests.head(url, timeout=timeout)
return True
except requests.ConnectionError:
print('No internet connection available.')
return False
def default_input(message, defaultVal):
if defaultVal:
return raw_input( "%s [%s]:" % (message, defaultVal) ) or defaultVal
else:
return raw_input( "%s :" % (message) )
def create_config():
global cfg;cfg = {}
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0)) # connecting to a UDP address doesn't send packets
local_ip_address = s.getsockname()[0]
cfg['domoticz'] = {}
cfg['domoticz']['hostName'] = default_input('Domoticz web service IP address (or host name)', local_ip_address)
cfg['domoticz']['portNumber'] = default_input('Domoticz web service port number', 8080)
cfg['domoticz']['protocol'] = ''
while cfg['domoticz']['protocol'] <> 'http' and cfg['domoticz']['protocol'] <> 'https':
cfg['domoticz']['protocol'] = default_input('Domoticz web service communication protocol (http or https)', 'http')
if cfg['domoticz']['protocol'] <> 'http' and cfg['domoticz']['protocol'] <> 'https':
print 'Invalid value given for Domoticz web service communication protocol. It must be \'http\' or \'https\''
cfg['domoticz']['httpBasicAuth'] = {}
cfg['domoticz']['httpBasicAuth']['userName'] = \
default_input('Domoticz web service user name (leave blank if no username is needed)', '')
cfg['domoticz']['httpBasicAuth']['passWord'] = \
default_input('Domoticz web service password (leave blank if no passord is needed)', '')
cfg['domoticz']['devices'] = {}
cfg['domoticz']['devices']['device'] = []
cfg['system'] = {}
tmpdir = '/var/tmp' if os.path.isdir('/var/tmp') else '/tmp'
cfg['system']['tmpFolder'] = '/xxxx/yyyy'
while not os.path.isdir(cfg['system']['tmpFolder']):
cfg['system']['tmpFolder'] = default_input('Directory for app logging and storing access tokens', tmpdir)
if not os.path.isdir(cfg['system']['tmpFolder']):
print 'That isn\'t a valid directory name on Your system! Please try again.'
cfg['oAuth2ClientCredentials'] = {}
cfg['oAuth2ClientCredentials']['authorizationCode'] = 'xxxx'
cfg['oAuth2ClientCredentials']['clientId'] = ''
while len(cfg['oAuth2ClientCredentials']['clientId']) <> 32:
cfg['oAuth2ClientCredentials']['clientId'] = default_input('Your Nibe UpLink Application\'s Identifier', '')
if len(cfg['oAuth2ClientCredentials']['clientId']) <> 32:
print 'That doesn\'t look like a valid Identifier. Have a look at https://api.nibeuplink.com/Applications'
print 'Please try again'
cfg['oAuth2ClientCredentials']['clientSecret'] = ''
while len(cfg['oAuth2ClientCredentials']['clientSecret']) <> 44:
cfg['oAuth2ClientCredentials']['clientSecret'] = default_input('Your Nibe UpLink Application\'s secret', '')
if len(cfg['oAuth2ClientCredentials']['clientSecret']) <> 44:
print 'That doesn\'t look like a valid secret. Have a look at https://api.nibeuplink.com/Applications'
print 'Please try again'
# Do we already have a hardware device named 'NIBEUplink' in Domoticz?
payload = dict([('type', 'hardware')])
r = domoticzAPI(payload)
hwIdx = '0'
HWNAME = 'NIBEUplink'
if 'result' in r.keys():
for hw in r['result']:
if hw['Name'] == HWNAME and hw['Enabled'] == 'true':
hwIdx = hw['idx']
break
if hwIdx <> '0':
cfg['domoticz']['virtualHwDeviceIdx'] = int(hwIdx)
else:
# Create a new Hardware Device. We wants it, we needs it. Must have the precious. They stole it from us!
payload = dict([('type', 'command'), ('param', 'addhardware'), ('htype', 15), \
('port', 1), ('name', HWNAME), ('enabled', 'true'), ('datatimeout', 0)])
r = domoticzAPI(payload)
# Now go fishing for the hardware device Idx
payload = dict([('type', 'hardware')])
r = domoticzAPI(payload)
for hw in r['result']:
if hw['Name'] == HWNAME and hw['Enabled'] == 'true':
hwIdx = hw['idx']
break
if hwIdx <> '0':
cfg['domoticz']['virtualHwDeviceIdx'] = int(hwIdx)
else:
print 'Can not find the newly created virtual hardware device.'
sys.exit(0)
# ROOM PLAN
# Do we already have a room plane named 'NIBEUplink' in Domoticz?
payload = dict([('type', 'plans')])
r = domoticzAPI(payload)
roomIdx = '0'
ROOMPLAN = 'NIBEUplink'
if 'result' in r.keys(): # Can happen if there are no room plans
for room in r['result']:
if room['Name'] == ROOMPLAN:
roomIdx = room['idx']
break
if roomIdx <> '0':
cfg['domoticz']['roomPlan'] = int(roomIdx)
else:
# Create a new Room Plan
payload = dict([('type', 'command'), ('param', 'addplan'), ('name', ROOMPLAN)])
r = domoticzAPI(payload)
# Now go fishing for the room plan Idx
payload = dict([('type', 'plans')])
r = domoticzAPI(payload)
for room in r['result']:
if room['Name'] == ROOMPLAN:
roomIdx = room['idx']
break
if roomIdx <> '0':
cfg['domoticz']['roomPlan'] = int(roomIdx)
else:
print 'Can not find the newly created room plan.'
sys.exit(0)
with open(cfgFile, 'w') as outfile:
json.dump(cfg, outfile, indent=2, sort_keys=True, separators=(',', ':'))
return cfg
def load_config():
try:
with open(cfgFile) as json_data_file:
cfg = json.load(json_data_file)
except IOError:
# Create a new config file
if tty:
cfg = create_config()
else:
sys.exit(0)
except:
logMessage = 'Can not open the config file ' + cfgFile
print logMessage, sys.exc_info()[0]
sys.exit(0)
return cfg
def domoticzAPI(payload):
try:
r = requests.get(cfg['domoticz']['protocol'] + '://' + cfg['domoticz']['hostName'] + ':' + \
str(cfg['domoticz']['portNumber']) + '/json.htm', \
verify=False, \
auth=(cfg['domoticz']['httpBasicAuth']['userName'], cfg['domoticz']['httpBasicAuth']['passWord']), \
params=payload)
except:
print('Can not open domoticz URL: \'' + cfg['domoticz']['protocol'] + '://' + cfg['domoticz']['hostName'] + ':' + \
str(cfg['domoticz']['portNumber']) + '/json.htm\'', sys.exc_info()[0])
sys.exit(0)
if r.status_code <> 200:
print 'Unexpected status code from Domoticz: ' + str(r.status_code)
sys.exit(0)
try:
rJsonDecoded = r.json()
except:
print('Can\'t Json decode response from Domoticz.', sys.exc_info()[0])
sys.exit(0)
if rJsonDecoded['status'] <> 'OK':
print 'Unexpected response from Domoticz: ' + rJsonDecoded['status']
sys.exit(0)
return rJsonDecoded
def logToDomoticz(messageType, logMessage):
payload = dict([('type', 'command'), ('param', 'addlogmessage'), \
('message', '(' + messageType+ ') ' + os.path.basename(sys.argv[0]) + ': ' + logMessage)])
r = domoticzAPI(payload)
return r
def truncate(x, d):
return int(x*(10.0**d))/(10.0**d)
def findTruncatedValue(rawValue, displayValue):
# Handle a case like this:
# "displayValue": "1339.3kWh", "rawValue": 133931
# "displayValue": "0.314kWh", "rawValue": 314931
# "displayValue": "-245DM", "rawValue": -2456
# "displayValue": "1341.6kWh", "rawValue": 134157
xTest = ''.join(ch for ch in displayValue if ch.isdigit() or ch == '.') # Now "1339.3"
if not xTest.lstrip('-').replace('.','',1).isdigit():
return ''
displayValueNum = float(xTest)
rawValue = abs(rawValue) # Now a positive number
if displayValueNum == rawValue or displayValueNum == 0 or rawValue == 0: return 1
# displayValueNum is now a number and it's not 0
if displayValueNum >= 1:
if int(rawValue / 10) == int(displayValueNum):
return 0.1
elif int(rawValue / 100) == int(displayValueNum):
return 0.01
elif int(rawValue / 1000) == int(displayValueNum):
return 0.001
else:
numDecimalPlaces = len(str(displayValueNum).split('.')[1]) # How many decimal places is there in displayValueNum ?
rawValueFloat = float(rawValue)
if truncate(rawValueFloat / 10, numDecimalPlaces) == displayValueNum:
return 0.1
elif truncate(rawValueFloat / 100, numDecimalPlaces) == displayValueNum:
return 0.01
elif truncate(rawValueFloat / 1000, numDecimalPlaces) == displayValueNum:
return 0.001
elif truncate(rawValueFloat / 10000, numDecimalPlaces) == displayValueNum:
return 0.0001
elif truncate(rawValueFloat / 100000, numDecimalPlaces) == displayValueNum:
return 0.00001
elif truncate(rawValueFloat / 1000000, numDecimalPlaces) == displayValueNum:
return 0.000001
return ''
def redefineDomoDevice(nibeSystem, nibeResource, nibeCategoryName):
global newDevicesList
global configChanged
for c in cfg['domoticz']['devices']['device']:
if c['nibeSystemId'] == nibeSystem['systemId'] and c['nibeParameterId'] == nibeResource['parameterId']:
devNameLong = ((nibeSystem['productName'] + ' ' + nibeResource['title'] + ' ' + nibeResource['designation']).title()).strip()
if not c['enabled']:
devNameLong += ' (Currently not enabled)'
elif c['domoticzIdx'] > 0:
devNameLong += ' (Enabled and current Domoticz idx: ' + str(c['domoticzIdx']) + ')'
if query_yes_no('Redefine : ' + devNameLong, 'no'):
configChanged = True # Do not append to newDevicesList
else:
newDevicesList.append(c)
def getDomoDevice(nibeSystem, nibeResource, nibeCategoryName):
unsupportedDevices = [ 0, 47214, 48745]
if nibeResource['parameterId'] in unsupportedDevices:
#print str(nibeResource['parameterId']) + ' is not a supported device'
return {}
#print str(nibeResource['nibeResourceId']) + ' is a supported device'
for c in cfg['domoticz']['devices']['device']:
if c['nibeSystemId'] == nibeSystem['systemId'] and c['nibeParameterId'] == nibeResource['parameterId']:
#print 'Found : ' + c['nibeTitle']
return c
if not tty:
return {}
nibeResource['title'] = nibeResource['title'].strip()
devNameLong = ((nibeSystem['productName'] + ' ' + nibeResource['title'] + ' ' + nibeResource['designation']).title()).strip()
nibeResource['title'] = nibeResource['title'].replace('compressor', 'compr')
nibeResource['title'] = nibeResource['title'].replace('compr.', 'compr')
if len(nibeResource['title']) > 17:
nibeResource['title'] = nibeResource['title'].replace('operating', 'op')
if nibeResource['unit'] == 'kWh':
# Counter incremental has very little space in the title
if len(nibeResource['title']) > 17:
nibeResource['title'] = nibeResource['title'].replace('factor', 'fc')
if len(nibeResource['title']) > 21:
nibeResource['title'] = nibeResource['title'][0:21].strip()
elif nibeResource['unit'] == 'A':
# Current meter, Add phase number to name
nibeResource['title'] = nibeResource['title'] + ' (Phase-' + nibeResource['designation'][-1:] + ')'
else:
if len(nibeResource['title']) > 36:
nibeResource['title'] = nibeResource['title'][0:36].strip()
# Avoid dulicate device names for 'heat medium flow'
if nibeResource['title'] == 'heat medium flow': nibeResource['title'] = nibeResource['title'] + ' ' + nibeResource['designation']
productNameShort = nibeSystem['productName'][5:] if nibeSystem['productName'][0:5] == 'NIBE ' else nibeSystem['productName']
devName = (productNameShort + ' ' + nibeResource['title']).title() # Capitalize the first letter of each word
createDev = default_input('\n\nFound a new Nibe Uplink resource: \'' + devNameLong + '\'\nShall I enable it and create a Domoticz Virtual Device for it? : Y/N', 'N')
createDev = (createDev.upper() == 'Y' or createDev.upper() == 'YES') and True or False
entry = {}
entry['enabled'] = False
entry['domoticzIdx'] = 0
if (nibeResource['displayValue'] == 'no' and nibeResource['rawValue'] == 0) \
or (nibeResource['displayValue'] == 'yes' and nibeResource['rawValue'] == 1):
entry['domoticzSensorType'] = 6 # Switch
elif nibeResource['parameterId'] in {9999999,47412} :# Hard coded for alarm
entry['domoticzSensorType'] = 7 # Alert
elif nibeResource['parameterId'] == 43416: # Hard coded for compressor starts, nibeResource['unit'] = ''
entry['domoticzSensorType'] = 113 # Counter sensor (Ordinary)
elif nibeResource['parameterId'] == 10069: # Hard coded for Smart Price Adaption
entry['domoticzSensorType'] = 1004 # Custom sensor
elif nibeResource['unit'] == '%':
entry['domoticzSensorType'] = 2 # Percentage
elif unicode(nibeResource['unit']) == u'\xb0'+'C':
entry['domoticzSensorType'] = 80 # Temp
elif nibeResource['unit'] == 'h' or nibeResource['unit'] == 's':
entry['domoticzSensorType'] = 113 # Counter sensor (Ordinary)
elif nibeResource['unit'] == 'Hz':
entry['domoticzSensorType'] = 1004 # Custom sensor
elif nibeResource['unit'] == 'kWh':
entry['domoticzSensorType'] = 113 # Counter sensor (Ordinary)
elif nibeResource['unit'] == 'kW':
entry['domoticzSensorType'] = 248 # Usage Electric
elif nibeResource['unit'] == 'A':
entry['domoticzSensorType'] = 19 # (Ampere 1-Phase)
elif nibeResource['unit'] == 'DM': # Degree minutes
entry['domoticzSensorType'] = 1004 # Custom sensor
elif nibeResource['parameterId'] in {40050,43124} : # Hard coded for some unit-less devices
entry['domoticzSensorType'] = 1004 # Custom sensor
elif nibeResource['unit'] == '':
entry['domoticzSensorType'] = 5 # Text
else:
print 'Unknown Domoticz type: \'' + unicode(nibeResource['unit']) + '\''
entry['domoticzSensorType'] = 0
if createDev and entry['domoticzSensorType'] > 0:
# Create a Virtual Device
payload = dict([('type', 'createvirtualsensor'), ('idx', cfg['domoticz']['virtualHwDeviceIdx']), \
('sensorname', devName), ('sensortype', entry['domoticzSensorType'])])
if entry['domoticzSensorType'] == 1004:
payload['sensoroptions'] = '1;' + nibeResource['unit']
r = domoticzAPI(payload)
# Now go fishing for the newly created device idx
payload = dict([('type', 'devices')])
r = domoticzAPI(payload)
devIdx = 0
for dev in reversed(r['result']):
if dev['Name'] == devName and dev['HardwareID'] == cfg['domoticz']['virtualHwDeviceIdx']:
devIdx = dev['idx']
break
if devIdx <> '0':
entry['domoticzIdx'] = int(devIdx)
entry['enabled'] = True
print 'Created Domoticz virtual device (idx) : ' + str(devIdx)
else:
print 'Error: Can not find the newly created virtual device.'
sys.exit(0)
# Add the device to the Domoticz room plan
payload = dict([('type', 'command'), ('param', 'addplanactivedevice'), ('idx', cfg['domoticz']['roomPlan']), \
('activetype', 0), ('activeidx', devIdx)])
r = domoticzAPI(payload)
entry['nibeSystemId'] = nibeSystem['systemId']
entry['nibeParameterId'] = nibeResource['parameterId']
entry['nibeTitle'] = nibeResource['title']
entry['nibeDesignation'] = nibeResource['designation']
entry['nibeCategoryName'] = nibeCategoryName.strip()
if nibeResource['parameterId'] == 43084: # This guy may be 0 for the moment making it hard to guess the factor
entry['valueFactor'] = 0.01
elif nibeResource['parameterId'] == 40016: # Brine out should have 0.1
entry['valueFactor'] = 0.1
elif nibeResource['parameterId'] == 40079: # Current should have 0.1
entry['valueFactor'] = 0.1
elif nibeResource['parameterId'] == 40081: # Current should have 0.1
entry['valueFactor'] = 0.1
elif nibeResource['parameterId'] == 40083: # Current should have 0.1
entry['valueFactor'] = 0.1
elif nibeResource['displayValue'] == '---':
entry['valueFactor'] = 1
elif nibeResource['displayValue'] == 'no' or nibeResource['displayValue'] == 'yes' or \
nibeResource['rawValue'] == -32768:
entry['valueFactor'] = 0
elif (nibeResource['rawValue'] == 0) and ('0.000' in nibeResource['displayValue']):
entry['valueFactor'] = 0.001
elif (nibeResource['rawValue'] == 0) and ('0.00' in nibeResource['displayValue']):
entry['valueFactor'] = 0.01
elif (nibeResource['rawValue'] == 0) and ('0.0' in nibeResource['displayValue']):
entry['valueFactor'] = 0.1 # This may not always be correct
elif (nibeResource['rawValue'] == 0):
entry['valueFactor'] = 1
elif str(nibeResource['rawValue'] * 1000) in nibeResource['displayValue']:
entry['valueFactor'] = 1000
elif str(nibeResource['rawValue'] * 100) in nibeResource['displayValue']:
entry['valueFactor'] = 100
elif str(nibeResource['rawValue'] * 10) in nibeResource['displayValue']:
entry['valueFactor'] = 10
elif str(nibeResource['rawValue']) in nibeResource['displayValue']:
entry['valueFactor'] = 1
elif str(nibeResource['rawValue'] / 10) in nibeResource['displayValue']:
entry['valueFactor'] = 0.1
elif str(nibeResource['rawValue'] / 100) in nibeResource['displayValue']:
entry['valueFactor'] = 0.01
elif findTruncatedValue(nibeResource['rawValue'], nibeResource['displayValue']) <> '':
entry['valueFactor'] = findTruncatedValue(nibeResource['rawValue'], nibeResource['displayValue'])
else:
entry['valueFactor'] = 1
# Change the Domoticz device if it was just created above
# We put this here because now we can access the entry['valueFactor'] now
if createDev and entry['domoticzSensorType'] > 0:
# When there is a counter created, there is a possibility to change the units and set the offset value
domoSurpriseFc = 1000 if nibeResource['unit'] == 'kWh' else 1
if entry['domoticzSensorType'] == 113:
payload = dict([('type', 'setused'), ('idx', devIdx), ('description', 'Virtual sensor device for ' + devNameLong), \
('switchtype', 0 if nibeResource['unit'] == 'kWh' else 3), \
('addjvalue', nibeResource['rawValue']*entry['valueFactor'] * -1), \
('used', 'true'), ('name', devName), \
('options', 'VmFsdWVRdWFudGl0eSUzQVRpbWUlM0JWYWx1ZVVuaXRzJTNBaCUzQg==' if nibeResource['unit'] == 'h' else '')])
r = domoticzAPI(payload)
# The options sent above is the string 'ValueQuantity:Time;ValueUnits:h;' that has been URL encoded + Base64 encoded
cfg['domoticz']['devices']['device'].append(entry)
with open(cfgFile, 'w') as outfile:
json.dump(cfg, outfile, indent=2, sort_keys=True, separators=(',', ':'))
configChanged = True
return entry
def updateDomoDevice(domoDevice, nibeResource):
if not domoDevice['enabled']:
return
# Only update if the new value differs from the device value
# or if the device has not been updated for a while
payload = dict([('type', 'devices'), ('rid', domoDevice['domoticzIdx'])])
r = domoticzAPI(payload)
# Domoticz has another surprise going on when it comes to counters ... Energy (kWh) Gas (m3) Water (m3)
# The counter will be treated with the divider which is defined in the parameters in the application settings.
# For example if the counter is set to "Water" and the value is passed as liters, the divider must set to 1000
# (as the unit is m3).
# It should be used both when reading and writing values
domoSurpriseFc = 1000 if nibeResource['unit'] == 'kWh' else 1
# TODO check more cases
#print r['result'][0]['Data'] #data
#print r['result'][0]['LastUpdate']
if not 'result' in r.keys():
errMess = 'Failure getting data for domoticz device idx: ' + str(domoDevice['domoticzIdx'])
print errMess
logToDomoticz(MSG_ERROR, errMess)
return
xTest = ''.join(ch for ch in r['result'][0]['Data'] if ch.isdigit() or ch == '.' or ch == '-') # Now "-1339.3"
if xTest.lstrip('-').replace('.','',1).isdigit():
domoValueNum = float(xTest) * domoSurpriseFc # This contains the Domoticz device's value as a number
else:
domoValueNum = 0
# Now, looking for a reason to update the sensor
# Does the Domotic's sensor need an update in order not to time out?
sensorTimedOut = False
if 'HaveTimeout' in r['result'][0]:
if (r['result'][0]['HaveTimeout'] and ((datetime.now() - datetime.strptime(r['result'][0]['LastUpdate'], '%Y-%m-%d %H:%M:%S')).seconds >= 3000)):
sensorTimedOut = True
# Does the value reported from Nibe differ from the Domoticz device's value?
valueChanged = False
if domoDevice['domoticzSensorType'] == 7: # Handling the ALERT Device type
domoCompareValue = r['result'][0]['Level']
testValue = r['result'][0]['Data']
if testValue == 'Everything seems to be fine':
domoCompareValue = '9' # Old version used 'Everything seems to be fine', it's to long to fit. This test can be removed in next version.
nibeCompareValue = 4 if nibeResource['rawValue'] <> 0 else 1
elif domoDevice['domoticzSensorType'] == 6: # Handling the SWITCH Device type
domoCompareValue = r['result'][0]['Status']
nibeCompareValue = 'On' if nibeResource['rawValue'] == 1 else 'Off'
elif domoDevice['domoticzSensorType'] == 113:# These guys use an offset value that we need to deal with
# Comparing floats in Python is not as simple as it sounds, using str() as a workaround
if nibeResource['unit'] == 'kWh':
nibeCompareValue = str(float(nibeResource['rawValue']*domoDevice['valueFactor']*domoSurpriseFc))
domoCompareValue = str((domoValueNum / domoSurpriseFc - r['result'][0]['AddjValue'])*domoSurpriseFc)
else:
# Don't use fractionals
nibeCompareValue = int(nibeResource['rawValue']*domoDevice['valueFactor'])
domoCompareValue = int(domoValueNum / domoSurpriseFc - r['result'][0]['AddjValue'])
elif domoDevice['domoticzSensorType'] == 248 and nibeResource['unit'] == 'kW': # Usage Electric
nibeCompareValue = str(float(nibeResource['rawValue']*domoDevice['valueFactor']*1000))
domoCompareValue = str(domoValueNum)
else:
nibeCompareValue = str(float(nibeResource['rawValue']*domoDevice['valueFactor']))
domoCompareValue = str(domoValueNum)
if nibeCompareValue <> domoCompareValue: valueChanged = True
if isDebug:
print r['result'][0]['Name']
print 'N: ' + str(nibeCompareValue)
print 'D: ' + str(domoCompareValue)
print
elif isVerbose and (valueChanged or sensorTimedOut):
sayThis = 'Updating Domoticz device \'' + r['result'][0]['Name'] + '\' idx: ' + str(domoDevice['domoticzIdx']) + ' due to:'
if valueChanged: sayThis += ' <value changed>. New value is: ' + str(nibeCompareValue) + \
'. Old value was: ' + str(domoCompareValue) + '.'
if sensorTimedOut: sayThis += ' <time condition>'
print sayThis
if not valueChanged and not sensorTimedOut:
return
if domoDevice['domoticzSensorType'] == 7: # Handling the ALERT Device type
payload = dict([('type', 'command'), ('param', 'udevice'), ('idx', domoDevice['domoticzIdx']), \
('nvalue', nibeCompareValue), ('svalue', 'OK' if nibeCompareValue == 1 else 'Alert!')])
elif domoDevice['domoticzSensorType'] == 6: # Handling the SWITCH Device type
payload = dict([('type', 'command'), ('param', 'switchlight'), ('idx', domoDevice['domoticzIdx']), \
('switchcmd', nibeCompareValue)])
else: # All other sensor types
payload = dict([('type', 'command'), ('param', 'udevice'), ('idx', domoDevice['domoticzIdx']), \
('nvalue', 0), ('svalue', nibeCompareValue)])
r = domoticzAPI(payload)
# Retrieve the authorization code
# It will only run if the variable cfg['oAuth2ClientCredentials']['authorizationCode'] has not been set
def retrieve_authorization_code():
authorization_code_req = {
"response_type": 'code',
"client_id": cfg['oAuth2ClientCredentials']['clientId'],
"state": 'xyz',
"access_type": 'offline',
"redirect_uri": redirect_uri,
"scope": (r'READSYSTEM' +
r' WRITESYSTEM')
}
r = requests.get(authorizeEndpointUrl + "?%s" % urlencode(authorization_code_req),
allow_redirects=False)
print '\nAuthorization Code retrieval\n==========================\nCopy the URL below and paste into the adress bar of a web browser. After granting access on Nibe Uplink, Your browser will show You the Authorization Code. Then enter that code below .\n'
url = r.headers.get('location')
print baseEndPointUrl + url + '\n'
while len(cfg['oAuth2ClientCredentials']['authorizationCode']) <> 401:
cfg['oAuth2ClientCredentials']['authorizationCode'] = default_input('Authorization Code', '')
if len(cfg['oAuth2ClientCredentials']['authorizationCode']) <> 401:
print 'That doesn\'t look like a valid Authorization Code. Please try again.'
with open(cfgFile, 'w') as outfile:
json.dump(cfg, outfile, indent=2, sort_keys=True, separators=(',', ':'))
configChanged = True
return
# Request new OAuth2 tokens
def requestTokens(grant_type, refreshToken):
logToDomoticz(MSG_INFO, 'Requesting acess tokens using the ' + grant_type + ' grant type')
logging.basicConfig(filename=logFile,level=logging.DEBUG,format='%(asctime)s %(levelname)s %(message)s',filemode='w')
data={}
try:
if grant_type == 'authorization_code':
data={'grant_type' : grant_type, 'code' : cfg['oAuth2ClientCredentials']['authorizationCode'], 'client_id' : cfg['oAuth2ClientCredentials']['clientId'], 'client_secret' : cfg['oAuth2ClientCredentials']['clientSecret'], 'redirect_uri' : redirect_uri}
elif grant_type == 'refresh_token':
logging.info('Using Refresh Token: %s' % refreshToken)
data={'grant_type' : grant_type, 'refresh_token' : refreshToken, 'client_id' : cfg['oAuth2ClientCredentials']['clientId'], 'client_secret' : cfg['oAuth2ClientCredentials']['clientSecret']}
getTokens = requests.post(tokenEndpointUrl, data)
getTokens.raise_for_status()
newTokens = getTokens.json()
accessToken = newTokens['access_token']
expiresIn = newTokens['expires_in']
expiration = int(time.time()) + expiresIn
refreshToken = newTokens['refresh_token']
plistlib.writePlist({'Access Token':accessToken,'Refresh Token':refreshToken,'Expiration': expiration,}, tokenDictionaryFile)
logging.info('Got Access Token: %s' % accessToken)
logging.info('The Access Token is valid for : %s seconds' % expiresIn)
logging.info('Got Refresh Token: %s' % refreshToken)
#tokenPlist = plistlib.readPlist(tokenDictionaryFile)
except requests.exceptions.RequestException, e:
logMessage = 'Can\'t generate tokens: %s' % e
logging.error('========== ' + logMessage + ' ==========')
logToDomoticz(MSG_ERROR, logMessage)
if tty:
print logMessage
print 'The Authorization Code might be too old. Clearing it out so that You can request a new. Please run this script again.'
cfg['oAuth2ClientCredentials']['authorizationCode'] = 'xxxx'
with open(cfgFile, 'w') as outfile:
json.dump(cfg, outfile, indent=2, sort_keys=True, separators=(',', ':'))
print '\n\nBelow is some debugging help:\n=============================='
for k, v in data.iteritems():
print k, ' = ', v
print '\n\n'
sys.exit(0)
except:
logMessage = 'Can\'t create the token dictionary file'
logging.error('========== ' + logMessage + ' ==========')
logToDomoticz(MSG_ERROR, logMessage)
if tty:
print logMessage
sys.exit(0)
return accessToken
# Validate the OAuth2 tokens
def validateTokens():
# First let's read the Token Dictionary plist
accessTokenValid = False
try:
tokenPlist = plistlib.readPlist(tokenDictionaryFile)
refreshToken = tokenPlist["Refresh Token"]
accessToken = tokenPlist["Access Token"]
expiration = tokenPlist["Expiration"]
if expiration - time.time() > 30:
accessTokenValid = True
logMessage = 'Current access token valid for ' + str(int(expiration - time.time())) + ' seconds'
if isVerbose:
logToDomoticz(MSG_INFO, logMessage)
except:
if not tty:
logToDomoticz(MSG_ERROR, 'You need to run \'python ' + os.path.realpath(__file__) + '\' from a console to obtain a new Authorization Code')
sys.exit(0)
# No file!? Man that's bad. Maybe this is the first time the script runs. Let's make an Authorization Request
errorText = 'There is no dictionary file ' + tokenDictionaryFile + '' \
+ ' (That is perfectly normal if this is the first time that the script runs)'
logToDomoticz(MSG_ERROR, errorText)
if tty:
print errorText
accessToken = requestTokens('authorization_code', '')
accessTokenValid = True
if not accessTokenValid:
# The old refresh token is used to obtain a new access token and a new refresh token
accessToken = requestTokens('refresh_token', refreshToken)
return accessToken
def get_system_list(accessToken):
authorization_header = {"Authorization": "Bearer %s" % accessToken}
r = requests.get(baseEndPointUrl + "/api/v1/systems", headers=authorization_header)
if r.status_code == requests.codes.ok:
if isDebug: print 'HTTP/1.1 200 OK'
else:
print "Nibe server responded with an error code: ", r.status_code
sys.exit(0)
if isDebug: print "get_system_list: ", r.text, "\n"
return r.text
def get_system_status(accessToken, systemid):
authorization_header = {"Authorization": "Bearer %s" % accessToken}
r = requests.get(baseEndPointUrl + "/api/v1/systems/" + str(systemid) + "/status/system", headers=authorization_header)
if isDebug: print "get_system_status: ", r.text, "\n"
return r.text
def get_system_config(accessToken, systemid):
authorization_header = {"Authorization": "Bearer %s" % accessToken}
r = requests.get(baseEndPointUrl + "/api/v1/systems/" + str(systemid) + "/config", headers=authorization_header)
if isDebug: print "get_system_config: ", r.text, "\n"
return r.text
def get_system_unit_status(accessToken, systemid, systemUnitId):
authorization_header = {"Authorization": "Bearer %s" % accessToken}
r = requests.get(baseEndPointUrl + "/api/v1/systems/" + str(systemid) + "/status/systemUnit/" + systemUnitId, headers=authorization_header)
if isDebug: print "get_system_unit_status: ", r.text, "\n"
return r.text
def get_serviceinfoCategories(accessToken, systemid):
authorization_header = {"Authorization": "Bearer %s" % accessToken}
r = requests.get(baseEndPointUrl + "/api/v1/systems/" + str(systemid) + "/serviceinfo/categories?parameters=true", headers=authorization_header)
if isDebug: print "get_serviceinfoCategories: ", r.text + '\n'
return r.text
def list_systems(accessToken):
systemlist = json.loads(get_system_list(accessToken))
if isVerbose: print 'Number of systems: ' + str(systemlist['numItems'])
if isVerbose: print ''
for nibeSystem in systemlist['objects']:
if isVerbose: print 'Product Name: ' + nibeSystem['productName']
if isVerbose: print 'Serial number: ' + nibeSystem['serialNumber']
if isVerbose: print 'System ID: ' + str(nibeSystem['systemId'])
if isVerbose: print 'Has alarmed: ' + str(nibeSystem['hasAlarmed'])
if isVerbose: print ''
# climate system 1
systemUnitId = 0
if isDebug: systemUnitStatus0 = json.loads(get_system_unit_status(accessToken, nibeSystem['systemId'], str(systemUnitId)))
if isDebug: systemStatus = json.loads(get_system_status(accessToken, nibeSystem['systemId']))
serviceinfoCategories = json.loads(get_serviceinfoCategories(accessToken, nibeSystem['systemId']))
# Append the hasAlarmed to the serviceinfoCategories parameters
has_alarmed_dict = {'parameterId': 9999999,
'name': '9999999',
'title': 'system alarm',
'designation': '',
'unit': '',
'displayValue': str(int(nibeSystem['hasAlarmed'])),
'rawValue': int(nibeSystem['hasAlarmed'])
}
for s in serviceinfoCategories:
if s['categoryId'] == 'STATUS' :
s['parameters'].append(has_alarmed_dict)
if redefineDevices:
for s in serviceinfoCategories:
for nibeResource in s['parameters']: # nibeResources:
redefineDomoDevice(nibeSystem, nibeResource, s['name'])
if configChanged:
cfg['domoticz']['devices']['device'] = newDevicesList # Replace the devices list in config file
with open(cfgFile, 'w') as outfile:
json.dump(cfg, outfile, indent=2, sort_keys=True, separators=(',', ':'))
print '\n\n\n'
for s in serviceinfoCategories:
for nibeResource in s['parameters']: # nibeResources:
#catResources = json.loads(p)
domoDevice = getDomoDevice(nibeSystem, nibeResource, s['name'])
if domoDevice: updateDomoDevice(domoDevice, nibeResource)
#print "Unit: " + p['unit']
if configChanged:
logMessage = 'Updated the config file at ' + cfgFile
logToDomoticz(MSG_INFO, logMessage)
if isVerbose: print logMessage
def print_help(argv):
print 'usage: ' + os.path.basename(__file__) + ' [option] [-C domoticzDeviceidx|all] \nOptions and arguments'
print '-d : debug output (also --debug)'
print '-h : print this help message and exit (also --help)'
print '-v : verbose'
print '-V : print the version number and exit (also --version)'
print '-R : redefines devices in the config file (also --redefine)'
def main(argv):
global isDebug
global isVerbose
global redefineDevices;redefineDevices = False
try:
opts, args = getopt.getopt(argv, 'dhvVR', ['help', 'debug', 'version', 'redefine'])
except getopt.GetoptError:
print_help(argv)
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
print_help(argv)
sys.exit(0)
elif opt in ('-d', '--debug'):
isDebug = True
elif opt in ('-v'):
isVerbose = True
elif opt in ('-V', '--version'):
print PROGRAMNAME + ' ' + VERSION
sys.exit(0)
elif opt in ("-R", "--redefine"):
redefineDevices = True
if isDebug: print 'Debug is on'
if not tty: time.sleep( 5 ) # Give Domoticz some time to settle down from other commands running exactly at the 00 sec
global cfg; cfg = load_config()
global logFile; logFile = os.path.join(cfg['system']['tmpFolder'], os.path.basename(sys.argv[0]) + '.log')
global tokenDictionaryFile; tokenDictionaryFile = os.path.join(cfg['system']['tmpFolder'], 'nibeUpLink.plist')
if not connected_to_internet():
logToDomoticz(MSG_ERROR, 'No internet connection available')
sys.exit(0)
msgProgInfo = PROGRAMNAME + ' Version ' + VERSION
msgProgInfo += ' running on TTY console...' if tty else ' running as a CRON job...'
if isVerbose:
print msgProgInfo
logToDomoticz(MSG_EXEC, msgProgInfo)
if len(cfg['oAuth2ClientCredentials']['authorizationCode']) <> 401:
if tty:
retrieve_authorization_code()
else:
sys.exit(0)
accessToken = validateTokens()
if redefineDevices and tty:
print '\nYou have requested to redefine the devices. By doing that, for each device found in your Nibe system, you will be asked if you want to redefine it. After going through the complete list, for any device that You answered \'Yes\' You will be asked if You want to create a Domoticz device for it.\n'
if not query_yes_no('Are You sure that you\'d like to redefine the devices', 'no'):
sys.exit(0)
list_systems(accessToken)
sys.exit(0)
if __name__ == '__main__':
main(sys.argv[1:])
-
- Posts: 5
- Joined: Saturday 09 September 2017 22:29
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 4.9700
- Contact:
Re: Domoticz RPC for NIBE Uplink
Does anyone know how safe it is to use these kind of redirect_uri, as these are external Links from an unknown site....Cossy wrote: ↑Wednesday 11 September 2019 19:10 I did make a simple adjustment by changing the call back url to the following:
redirect_uri = "https://www.marshflattsfarm.org.uk/nibe ... /index.php" # Don't alter this or anything else!
Based on the blog post of: https://www.marshflattsfarm.org.uk/word ... ge_id=3480 which did the trick for me and it now working for multiple hours.
Tempting to do a cleanup later as well, anybody else still working on this code?
-
- Posts: 1
- Joined: Friday 03 April 2020 17:34
- Target OS: Raspberry Pi / ODroid
- Domoticz version:
- Contact:
Re: Domoticz RPC for NIBE Uplink
The source code uses: redirect_uri = "http://showquerystring.000webhostapp.com/index.php"
This and the alternativ :"https://www.marshflattsfarm.org.uk/nibe ... h2callback" aren't valid for new installations.
Can someone help me with building my own weppage for this authentification proces from Nibe.
By the way, This software has now been released according to the GNU General Public License. I can't find it at Github.
This and the alternativ :"https://www.marshflattsfarm.org.uk/nibe ... h2callback" aren't valid for new installations.
Can someone help me with building my own weppage for this authentification proces from Nibe.
By the way, This software has now been released according to the GNU General Public License. I can't find it at Github.
-
- Posts: 13
- Joined: Thursday 09 May 2019 18:24
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2020.2
- Location: NL
Re: Domoticz RPC for NIBE Uplink
I started to implement the python script. Unfortunately it stops in the function "requestTokens" .
It continually falls into the exception saying that it can't create the dictionary file. I do not think that that is the problem. I have even set the directory to full read/write rights.
Anyone experienced this same problem? Any help or suggestions are appreciated.
It continually falls into the exception saying that it can't create the dictionary file. I do not think that that is the problem. I have even set the directory to full read/write rights.
Anyone experienced this same problem? Any help or suggestions are appreciated.
Raspberry PI 3 &4; Hue Bridge * 2; Zwave devices: FGD212 * 22, FGS222 * 4, FGSD002 * 3, FGMS002 * 5, Qubino ZMNHXD 3 Phase meter * 3 ; P1 smart meter; Foscam camera *2; Solaredge inverter and solarpanels * 2, NIBE 1255-06 PC heat pump
-
- Posts: 13
- Joined: Thursday 09 May 2019 18:24
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2020.2
- Location: NL
Re: Domoticz RPC for NIBE Uplink
Forget about my previous post. This was due to being novice in Python programming.
But now I get to the real issue the error message below:
Can't generate tokens: HTTPSConnectionPool(host='api.nibeuplink.com', port=443): Max retries exceeded with url: /oauth/token (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0xb5bc30b0>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',))
The Authorization Code might be too old. Clearing it out so that You can request a new. Please run this script again.
The authorizationcode was freshly retrieved. Any ideas?
But now I get to the real issue the error message below:
Can't generate tokens: HTTPSConnectionPool(host='api.nibeuplink.com', port=443): Max retries exceeded with url: /oauth/token (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0xb5bc30b0>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',))
The Authorization Code might be too old. Clearing it out so that You can request a new. Please run this script again.
The authorizationcode was freshly retrieved. Any ideas?
Raspberry PI 3 &4; Hue Bridge * 2; Zwave devices: FGD212 * 22, FGS222 * 4, FGSD002 * 3, FGMS002 * 5, Qubino ZMNHXD 3 Phase meter * 3 ; P1 smart meter; Foscam camera *2; Solaredge inverter and solarpanels * 2, NIBE 1255-06 PC heat pump
Re: Domoticz RPC for NIBE Uplink
I have same situation. Old system works ok, but I need to migrate Domoticz to new platform. I added new application to Nibe uplink to avoid messing up the old setup. I can create new auth code using new app id and secret but get similar error as ceesgeert.
Can't generate tokens: 400 Client Error: Bad Request for url: https://api.nibeuplink.com/oauth/token
The Authorization Code might be too old. Clearing it out so that You can request a new. Please run this script again.
Can't generate tokens: 400 Client Error: Bad Request for url: https://api.nibeuplink.com/oauth/token
The Authorization Code might be too old. Clearing it out so that You can request a new. Please run this script again.
Re: Domoticz RPC for NIBE Uplink
It started to work after deleting old /var/tmp/nibeUpLink.plist and then running nibeuplink.py again.
-
- Posts: 9
- Joined: Wednesday 28 December 2016 13:51
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 3.8153
- Location: Netherlands
- Contact:
Re: Domoticz RPC for NIBE Uplink
Hi, I'm tyring to add the Nibe to my system but I'm getting the following ressponse. What am I dowing wrong?
The callback URL (https://www.marshflattsfarm.org.uk/nibe ... h2callback) is not allowed for this client.
The callback URL (https://www.marshflattsfarm.org.uk/nibe ... h2callback) is not allowed for this client.
-
- Posts: 17
- Joined: Tuesday 06 March 2018 11:24
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2022.1
- Contact:
Re: Domoticz RPC for NIBE Uplink
Hi all.
I'm using Nibeuplink for Domoticz already for a few years and it works really great.
But now I've the following problem and not being a python programmer I can't solve it completely.
The problem.
This week I finally got glasfibre installed. There's a new modem etc. and my home network appeared after this to be on a new submask, 192.168.1.xxx instead of 192.168.2.xxx it was. No big problem, the changes took some work but every PC, NAS etc. worked after a while, as well as the RPi's. Also Domoticz worked great as always, only the data from NIBE won't update anymore. The NIBE heatpump itself can be reached normally, no problem.
So I tried to look where this Nibeuplink script should need a change and that's in config.json: I updated the network address and thought it would be ok now, but it isn't. Every 5 minutes I get a mail from Cron <root@Raspberry> /usr/bin/python /home/pi/domoticz/scripts/NibeUplink/nibeuplink.py now saying :
That's when I went to create new authorisation as described, running the nibeuplink.py script.
Well, that doesn't run anymore, many errors were displayed that pobably were caused by running on Python 3.8 instead of the former 2.7 when I installed this. Anyway, I changed a lot like all "<>" to "!=" etc. etc.
It looks like most errors are solved but not all. At this moment the problem is this: I can run the script again, I do get the link to /api.nibeuplink.com and that starts. But after I fill in the credentials to enter my apllication, I get following screen that's displayed at http://showquerystring.000webhostapp.co ... &state=xyz stating that the website is no longer available.
Does anybody know how to solve this problem? I've no idea how to continue...
As it looks to me now, the problem should be in line 12 of the python script, my changes are all in place so no new or deleted lines. But how to solve that import requests I can't get working.
This specific command on line 12 is :
Off course I tried to find it via Google and the last I found was to change this command to:
but it's still having a problem with the parse (invalid syntax).
Long stoy short: I can't get it working again, it looks like the script doesn't work entirely properly in Python3.
Your help would be appreciated very much!!
I'm using Nibeuplink for Domoticz already for a few years and it works really great.
But now I've the following problem and not being a python programmer I can't solve it completely.
The problem.
This week I finally got glasfibre installed. There's a new modem etc. and my home network appeared after this to be on a new submask, 192.168.1.xxx instead of 192.168.2.xxx it was. No big problem, the changes took some work but every PC, NAS etc. worked after a while, as well as the RPi's. Also Domoticz worked great as always, only the data from NIBE won't update anymore. The NIBE heatpump itself can be reached normally, no problem.
So I tried to look where this Nibeuplink script should need a change and that's in config.json: I updated the network address and thought it would be ok now, but it isn't. Every 5 minutes I get a mail from Cron <root@Raspberry> /usr/bin/python /home/pi/domoticz/scripts/NibeUplink/nibeuplink.py now saying :
Code: Select all
Traceback (most recent call last):
File "/home/pi/domoticz/scripts/NibeUplink/nibeuplink.py", line 12, in <module>
import requests
ImportError: No module named requests
Well, that doesn't run anymore, many errors were displayed that pobably were caused by running on Python 3.8 instead of the former 2.7 when I installed this. Anyway, I changed a lot like all "<>" to "!=" etc. etc.
It looks like most errors are solved but not all. At this moment the problem is this: I can run the script again, I do get the link to /api.nibeuplink.com and that starts. But after I fill in the credentials to enter my apllication, I get following screen that's displayed at http://showquerystring.000webhostapp.co ... &state=xyz stating that the website is no longer available.
Does anybody know how to solve this problem? I've no idea how to continue...
As it looks to me now, the problem should be in line 12 of the python script, my changes are all in place so no new or deleted lines. But how to solve that import requests I can't get working.


Code: Select all
import requests
from urllib.parse import urlencode
Code: Select all
import requests
from urllib.parse.urlencode(import)
Long stoy short: I can't get it working again, it looks like the script doesn't work entirely properly in Python3.
Your help would be appreciated very much!!
Nibe F1255-6 PC heatpump, SolarEdge SE7K inverter + 16 x Solarwatt panels (in-roof 275Wp) + 12 x AEG panels 325Wp+ optimizers, EtaSunPro vacuum collector (60 tubes)
-
- Posts: 17
- Joined: Tuesday 06 March 2018 11:24
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2022.1
- Contact:
Re: Domoticz RPC for NIBE Uplink
After testen various other things without succes and being a bit sick of it, I finally did a restore of the entire SD-card with Raspibackup with a tar-backup of a week ago. After that succeeded, I wrote the recent Domoticz data to that card and editted config.json of Nibeuplink again for the now correct IP-address (at the end of the file).
In fact this is all exactly the same as I did in the beginning (only changing that IP-address), but to my giant supprise it's working now
Of course I'm really very happy, although I don't understand why (which is a little bit frustrating
). I compared the config.json I used in the not-working version, it's exactly the same. Also Python is the same 3.8 version, so it beats me completely. Of course I somewhere will have made a mistake, but I feel a bit stupid not being able to find out what caused these problems
Anyway, since this problem seems to be gone now I won't try if running nibeuplink.py works again normally. Maybe someone runs nibeuplink.py again for authorisation and doesn't have any of the problems I wrote about, then that's perfect!
In fact this is all exactly the same as I did in the beginning (only changing that IP-address), but to my giant supprise it's working now

Of course I'm really very happy, although I don't understand why (which is a little bit frustrating


Anyway, since this problem seems to be gone now I won't try if running nibeuplink.py works again normally. Maybe someone runs nibeuplink.py again for authorisation and doesn't have any of the problems I wrote about, then that's perfect!
Nibe F1255-6 PC heatpump, SolarEdge SE7K inverter + 16 x Solarwatt panels (in-roof 275Wp) + 12 x AEG panels 325Wp+ optimizers, EtaSunPro vacuum collector (60 tubes)
- waltervl
- Posts: 5727
- Joined: Monday 28 January 2019 18:48
- Target OS: Linux
- Domoticz version: 2024.7
- Location: NL
- Contact:
Re: Domoticz RPC for NIBE Uplink
Thank you again, also added to the plugin list on the wiki https://www.domoticz.com/wiki/PluginsFlopp wrote: ↑Sunday 14 March 2021 23:59 Hi, maybe you can try my plug-in
https://github.com/flopp999/NIBEUplink-Domoticz
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
-
- Posts: 9
- Joined: Wednesday 28 December 2016 13:51
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 3.8153
- Location: Netherlands
- Contact:
Re: Domoticz RPC for NIBE Uplink
Hi Flopp,
Thank you for the plugin. It does not work for me unfortunately. In Domoticz I need to ener NIBE Refresh Token, where can I find this?
My accescode is also much much longer than on the Github exampe, is this correct?
The domoticz log :
2021-03-23 17:39:03.110 Error: (Nibe) 'onHeartbeat' failed 'AttributeError':''BasePlugin' object has no attribute 'GetToken''.
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 402 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 270 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
Thank you for the plugin. It does not work for me unfortunately. In Domoticz I need to ener NIBE Refresh Token, where can I find this?
My accescode is also much much longer than on the Github exampe, is this correct?
The domoticz log :
2021-03-23 17:39:03.110 Error: (Nibe) 'onHeartbeat' failed 'AttributeError':''BasePlugin' object has no attribute 'GetToken''.
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 402 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 270 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
-
- Posts: 279
- Joined: Sunday 03 January 2016 14:55
- Target OS: -
- Domoticz version:
- Location: Sweden
- Contact:
Re: Domoticz RPC for NIBE Uplink
Hi, the Refresh Token you should get in the Log. I have written "Copy Refresh Token from Log to here" in the field for Refresh Token.Timothy wrote: ↑Tuesday 23 March 2021 17:42 Hi Flopp,
Thank you for the plugin. It does not work for me unfortunately. In Domoticz I need to ener NIBE Refresh Token, where can I find this?
My accescode is also much much longer than on the Github exampe, is this correct?
The domoticz log :
2021-03-23 17:39:03.110 Error: (Nibe) 'onHeartbeat' failed 'AttributeError':''BasePlugin' object has no attribute 'GetToken''.
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 402 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
2021-03-23 17:39:03.110 Error: (Nibe) ----> Line 270 in '/home/pi/domoticz/plugins/NIBEUplink/plugin.py', function onHeartbeat
About Access Code, Copy everything between "...code=" and "&state...", it is a very long code so my code is just an example
I have now updated the text so it should be easier to understand that this is just an example, normal code i ~380 characters
-
- Posts: 9
- Joined: Wednesday 28 December 2016 13:51
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 3.8153
- Location: Netherlands
- Contact:
Re: Domoticz RPC for NIBE Uplink
ok, the code is correct then. What log are you refering to? I cannot find a Token in the log.
-
- Posts: 279
- Joined: Sunday 03 January 2016 14:55
- Target OS: -
- Domoticz version:
- Location: Sweden
- Contact:
Re: Domoticz RPC for NIBE Uplink
The access code can only be used once, I will add this to the text on GitHub.
So try with a new access code.
The log in Domoticz, will update the text with this
Thank you for helping me and others to understand my text.
When more people try to follow the guide it will finally one day be prefect

-
- Posts: 9
- Joined: Wednesday 28 December 2016 13:51
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 3.8153
- Location: Netherlands
- Contact:
Re: Domoticz RPC for NIBE Uplink
i've tryed to repeat the step to get a new acces code but it does not work anymore. The api.nibeuplink gives my the folowing error and the url does not change.
"Failure looking up secret for client or token."

"Failure looking up secret for client or token."
-
- Posts: 279
- Joined: Sunday 03 January 2016 14:55
- Target OS: -
- Domoticz version:
- Location: Sweden
- Contact:
Re: Domoticz RPC for NIBE Uplink
@TimothyTimothy wrote:
thank you very much @Timothy for your help and patience while I was checking the plugin.
We found some bugs which now shall be fixed
If more people can try the plugin I would be glad.
I will continue to develop the plugin after I get information from you users.
-
- Posts: 9
- Joined: Wednesday 28 December 2016 13:51
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 3.8153
- Location: Netherlands
- Contact:
Re: Domoticz RPC for NIBE Uplink
I've got it working now, after some tweaking with Flopp. The problem was in the application(s) in api.nibeuplink, and initially I put the wrong number in the access token link. Because I could not get it to work I created a new one. After testing en debugging for a couple of hours we (Flopp and I ) could not get this to work. When I switched back to the first application it worked right away. Why there was a difference in the 2 applications on api.uplink? I don't know.
Who is online
Users browsing this forum: No registered users and 1 guest