Giter Club home page Giter Club logo

python-openhab's Introduction

Documentation Status PyPI PyPI - Python Version

python library for accessing the openHAB REST API

This library allows for easily accessing the openHAB REST API. A number of features are implemented but not all, this is work in progress.

Requirements

  • python >= 3.8
  • python :: dateutil
  • python :: httpx
  • python :: authlib
  • openHAB version 3 / 4

Installation

Install the latest version using pip:

pip install python-openhab

Example

Example usage of the library:

from openhab import OpenHAB

base_url = 'http://localhost:8080/rest'
openhab = OpenHAB(base_url)

# fetch all items
items = openhab.fetch_all_items()

sunset = items.get('Sunset')
print(sunset.state)

# fetch a single item
item = openhab.get_item('light_switch')

# turn a switch on
item.on()

# send a state update (this only update the state)
item.state = 'OFF'

# send a command
item.command('ON')

# check if item state is NULL
if item.state is None and item.is_state_null():
    pass

# check if item state is UNDEF
if item.state is None and item.is_state_undef():
    pass

# fetch some group
lights_group = openhab.get_item('lights_group')

# send command to group
lights_group.on()

# send update to each member
for v in lights_group.members.values():
    v.update('OFF')

Note on NULL and UNDEF

In openHAB items may have two states named NULL and UNDEF, which have distinct meanings but basically indicate that an item has no usable value. This library sets the state of an item, regardless of their openHAB value being NULL or UNDEF, to None. This in order to ease working with the library as we do cast certain types to native types.

In order to check if an item's state is either NULL or UNDEF, you can use the helper functions:

item.is_state_null()
item.is_state_undef()

Experimental OAuth2 Support

In order to try out OAuth2 authentication, you first need to register with the openHAB endpoint in order to retrieve a token and refresh token.

Assuming your openHAB instance runs at http://127.0.0.1:8080 (replace with the correct one), use the following snippet to retrieve a token:

import pathlib
import openhab.oauth2_helper
import os
import json

url_base = 'http://127.0.0.1:8080'
api_username = 'admin'
api_password = 'admin'
oauth2_client_id = 'http://127.0.0.1/auth'
oauth2_token_cache = pathlib.Path(__file__).resolve().parent / '.oauth2_token_test'

# this must be set for oauthlib to work on http (do not set for https!)
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

oauth2_token = openhab.oauth2_helper.get_oauth2_token(url_base, username=api_username, password=api_password)

with oauth2_token_cache.open('w') as fhdl:
    json.dump(oauth2_token, fhdl, indent=2, sort_keys=True)

The JSON that is returned is required for authenticating to openHAB using OAuth2 as well as a refresh token which is used for refreshing a session.

Next try connecting to openHAB using this library as follows:

import openhab
import pathlib
import json
import os

url_base = 'http://127.0.0.1:8080'
url_rest = f'{url_base}/rest'
oauth2_client_id = 'http://127.0.0.1/auth'
oauth2_token_cache = pathlib.Path(__file__).resolve().parent / '.oauth2_token_test'

# this must be set for oauthlib to work on http (do not set for https!)
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

oauth2_config = {'client_id': oauth2_client_id,
                 'token_cache': str(oauth2_token_cache)
                 }

with oauth2_token_cache.open('r') as fhdl:
    oauth2_config['token'] = json.load(fhdl)

oh = openhab.OpenHAB(base_url=url_rest, oauth2_config=oauth2_config)

o = oh.get_item('test_item')
print(o)

python-openhab's People

Contributors

arroyoj avatar cedrikschueler avatar guppy avatar hexamer avatar jabote avatar martinvw avatar niebochod avatar pescobar avatar sim0nx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-openhab's Issues

Expose _unitOfMeasure

Hi! Currently in the code I see just one reference to _unitOfMeasure:

    if self.is_undefined(self._raw_state):
      self._state = None
    else:
      self._state, self._unitOfMeasure = self._parse_rest(self._raw_state)

The property is not initiated and it's not accessible from the API.

Would be great to get it separately.

Best regards and thank you for your hard work!

Openhab 3.0 OAuth2 authentification

With the new OpenHab 3.0 release the rest service is now using OAuth2 to authenticate users. Is this already possible with this library or will this feature be added in the future?

Rollershutter type not supported

python-openhab does not involve the rollershutter type.
As a workaround there are two ways:

  1. Changing the items to Dimmer in openHAB

foo.items (click for expansion)
// e.g. from this:
Rollershutter   Shutter      "Jalousie"                  <rollershutter>   (LivingRoom, gShutter)   ["Rollershutter"]                  {channel=""}
// to this
Dimmer   Shutter      "Jalousie"                  <rollershutter>   (LivingRoom, gShutter)   ["Rollershutter"]                  {channel=""}

  1. Assigning the rollershutter to a DimmerItem in python-openhab

client.py (click for expansion)
  # in line 199
  elif json_data['type'] in ['Dimmer', 'Rollershutter']:
    return openhab.items.DimmerItem(self, json_data)

Maybe a RollershutterItem should be defined?

AttributeError: 'Session' object has no attribute 'requests

Hi there
i try to make the program safe even with connection problems.
if iptest():
print(WertI)
try:
Item.state = WertI
except openhab.session.requests.exceptions.HTTPError as errh:
print (DT + "Http Error:",errh)
ErrorLog = open (DT + 'ErrorLog.txt', 'a')
ErrorLog.write (DT + "Http Error: %d \n" % errh)
ErrorLog.close()
return
except openhab.session.requests.exceptions.ConnectionError as errc:
print (DT + "Error Connecting:",errc)
ErrorLog = open (DT + 'ErrorLog.txt', 'a')
ErrorLog.write (DT + "Error Connecting: %d \n" % errc)
ErrorLog.close()
return
except openhab.session.requests.exceptions.Timeout as errt:
print (DT + "Timeout Error:",errt)
ErrorLog = open (DT + 'ErrorLog.txt', 'a')
ErrorLog.write (DT + "Timeout Error:%d \n" % errt)
ErrorLog.close()
return
except:
print (DT + "any Error:")
ErrorLog = open (DT + 'ErrorLog.txt', 'a')
ErrorLog.write (DT + "any Error" + "\n")
ErrorLog.close()
return
else:
Untbr = Untbr +1

The Problem is
except openhab.session.requests.exceptions.HTTPError as errh:
AttributeError: 'Session' object has no attribute 'requests'

Tanks and a "Happy new Year "

Reference information to this repository

As our project group at university is coming to an end we are currently writing some documentation.

As your project was a nice tool for us to request the openHAB Rest-API in a safe way we would like to put a reference to you in our documentation (even if it might not be published anywhere).

Is this bib-entry okay?

@misc{python-openhab,
    author = "Georges Toth",
    title = "Python-openHAB: python library for accessing the openHAB REST API",
    url = "github.com/sim0nx/python-openhab"
}

Thanks for your project and feedback!

Wrong capitalization in example throws error

From the very example at the PyPI web page:

from openhab import openHAB

base_url = 'http://localhost:8080/rest'
openhab = OpenHAB(base_url)

# fetch all items
items = openhab.fetch_all_items()

Python 3.7 answer:

Traceback (most recent call last):
  File "[[ommitted]]", line 4, in <module>
    openhab = OpenHAB(base_url)
NameError: name 'OpenHAB' is not defined

Fixes correcting capitalization in the import line or the openhab variable declaration.

model_dump error: pydantic 2.0 vs pydantic 1.10

Hello,

Latest openhab code requires pydantic 2.0

token=self.oauth2_config.token.model_dump(),

model_dump is absent in pydantic 1.10

it it possible to adapt openhab code to pydantic 1.10 ?
I try to add pydantic 2.0 to manifest.json, but always receive

Cannot install pydantic==2.* because these package versions have conflicting dependencies.

have no ideas ...

Problem with groups in OpenHAB 3

For me the library can not read the members of a group in OpenHAB 3. From what i have seen the members of a group are determined with these lines of code:
for i in json_data['members']: self.members[i['name']] = self.openhab.json_to_item(i)

When I access my servers REST interface with ip:8080/rest/items , I see that the group itself does not save its members. Instead each member remembers the groups it is in (see pictures).

Is this issue only occuring for me or is it a problem in general? I would try to fix it and commit if it is a problem in general.

Thank you!

A group thing:
Group

A "normal" thing:
Thing

error updating items with non-latin strings

Hi,
I am trying to update a string item with non-latin characters.
when I do:
routetowork.state = 'שלום'

the PUT fails :

  File "/usr/lib/python3.7/http/client.py", line 1244, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/lib/python3.7/http/client.py", line 1289, in _send_request
    body = _encode(body, 'body')
  File "/usr/lib/python3.7/http/client.py", line 170, in _encode
    (name.title(), data[err.start:err.end], name)) from None
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-3: Body ('שלום') is not valid Latin-1. Use body.encode('utf-8') if you want to send it encoded in UTF-8.

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-3
when I do:

routetowork.state = 'שלום'.encode('utf-8')

I get

File "/usr/local/lib/python3.7/dist-packages/openhab/items.py", line 109, in _validate_value
    raise ValueError()

if I leave the .encode('utf-8') and comment line 163:
#self._validate_value(value)
everything works.

Thanks,

Setting items state to NULL and UNDEF

Is there a way to set an item state to NULL or UNDEF? I tried python's None and strings "NULL", "UNDEF" and "", but they all raise an Invalid Value exception.

Connection Error, Connection aborted

Connection between openHAB 2.5.0 Release Build on Raspberry pi and an other Raspberry pi with
a Python 3 program aborted after hours.

Traceback (most recent call last):
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 672, in urlopen
chunked=chunked,
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 421, in _make_request
six.raise_from(e, None)
File "", line 3, in raise_from
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 416, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib/python3.5/http/client.py", line 1198, in getresponse
response.begin()
File "/usr/lib/python3.5/http/client.py", line 297, in begin
version, status, reason = self._read_status()
File "/usr/lib/python3.5/http/client.py", line 266, in _read_status
raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/pi/.local/lib/python3.5/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 720, in urlopen
method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/util/retry.py", line 400, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/packages/six.py", line 734, in reraise
raise value.with_traceback(tb)
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 672, in urlopen
chunked=chunked,
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 421, in _make_request
six.raise_from(e, None)
File "", line 3, in raise_from
File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 416, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib/python3.5/http/client.py", line 1198, in getresponse
response.begin()
File "/usr/lib/python3.5/http/client.py", line 297, in begin
version, status, reason = self._read_status()
File "/usr/lib/python3.5/http/client.py", line 266, in _read_status
raise RemoteDisconnected("Remote end closed connection without"
urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "PyCanTest_R.py", line 125, in
state=recv_Mess() # initial state
File "PyCanTest_R.py", line 114, in recv_Mess
datWand(s,listTemp,"13FE04","Aussentemperatur: ")
File "PyCanTest_R.py", line 78, in datWand
AussentpRoh.state = WertI
File "/home/pi/.local/lib/python3.5/site-packages/openhab/items.py", line 76, in state
self.update(value)
File "/home/pi/.local/lib/python3.5/site-packages/openhab/items.py", line 131, in update
self.openhab.req_put('/items/{}/state'.format(self.name), data=v)
File "/home/pi/.local/lib/python3.5/site-packages/openhab/client.py", line 134, in req_put
r = self.session.put(self.base_url + uri_path, data=data, timeout=self.timeout)
File "/home/pi/.local/lib/python3.5/site-packages/requests/sessions.py", line 593, in put
return self.request('PUT', url, data=data, **kwargs)
File "/home/pi/.local/lib/python3.5/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/home/pi/.local/lib/python3.5/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/home/pi/.local/lib/python3.5/site-packages/requests/adapters.py", line 498, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))

The 'pip==20.3.4' distribution was not found and is required by the application

i get the following error:

clean install of python3.11

File "/usr/local/lib/python3.11/site-packages/pip/_vendor/pkg_resources/init.py", line 868, in _resolve_dist
raise DistributionNotFound(req, requirers)
pip._vendor.pkg_resources.DistributionNotFound: The 'pip==20.3.4' distribution was not found and is required by the application

Number:Temperature items are not updated

My item in openHAB:
Number:Temperature BoilerTemperature "BoilerTemperatur [%.1f °C]"

My python coding:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from openhab import openHAB

#openHAB Verbindung 
base_url = 'http://192.168.XXX.XX:8080/rest'
openhab = openHAB(base_url)

...

BoilerTemperature = openhab.get_item('BoilerTemperature')
...
BoilerTemperature.command("58.5")`

When running this code I get following error message (on a MAC):

Traceback (most recent call last):
File "/Users/georg/Documents/python/test2.py", line 24, in
BoilerTemperature.command("58.5")
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/openhab/items.py", line 141, in command
self._validate_value(value)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/openhab/items.py", line 99, in _validate_value
raise ValueError()
ValueError

It seems to be a validation error in the "openHAB" coding. If I change to a "straight" Number item the update works without any problem.
Thanks for support
Georg

Item Types

Hi there. Just wondering what item types that are defined in this library. I noticed you have a general Item object and a SwitchItem too. I would like to set the state of a dimmer light to 50 but 'light.state = '50'' does not work for me. Thanks!

Contact Item not valid

I just found out the following bug:

If you try to set the state of a contact item it fails with an value error

    raise ValueError('Invalid value "{}"'.format(value))
ValueError: Invalid value "CLOSED"

If you take a look on the documentation this makes sense as the contact item is a "read only" item (click for documentation).

Anyways there are still functions implemented to set the state.
This might affect other item types too!

Support persistent method

Hello,

thank you for this librarzy. I am using this for writing logic in Python.
It would help me to use persisten REST service. Are you planning to support get date for the item based on persistent REST?

Thanks
Jirka

invocation fails

attempting to update a string via python:

Traceback (most recent call last):
File "./readPower.py", line 3, in
from openhab import openHAB
File "/usr/local/lib/python3.5/dist-packages/openhab/init.py", line 1, in
from .client import openHAB, OpenHAB
File "/usr/local/lib/python3.5/dist-packages/openhab/client.py", line 30, in
import openhab.items
File "/usr/local/lib/python3.5/dist-packages/openhab/items.py", line 34, in
class Item:
File "/usr/local/lib/python3.5/dist-packages/openhab/items.py", line 78, in Item
def _validate_value(self, value: typing.Union[str, typing.Type[openhab.types.CommandType]]):
File "/usr/lib/python3.5/typing.py", line 552, in getitem
dict(self.dict), parameters, _root=True)
File "/usr/lib/python3.5/typing.py", line 512, in new
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
File "/usr/lib/python3.5/typing.py", line 512, in
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
File "/usr/lib/python3.5/typing.py", line 1077, in subclasscheck
if super().subclasscheck(cls):
File "/usr/lib/python3.5/abc.py", line 225, in subclasscheck
for scls in cls.subclasses():
TypeError: descriptor 'subclasses' of 'type' object needs an argument

Script in use, based on examples:

`#! /usr/bin/python3

from openhab import openHAB
import urllib
import socket
import time

base_url = 'http://localhost:8080/rest'
openhab = openHAB(base_url)

timeout = 20
socket.setdefaulttimeout(timeout)

link = "http://192.168.1.1/instantaneousdemand"

while True:
try:
myitem = openhab.get_item("InstantPowerConsumption")
f = urllib.urlopen(link)
myfile = f.read()
if myfile != "000000.000 kW":
myitem.state = myfile
time.sleep(10)
except:
time.sleep(10)
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.