Converting UI items back to *.items File

yes that is true, you need a wide monitor to display them all on a single line :wink:
It probably all depends on how often you use a text editor and add new sensors. Currently I’m expanding my system a lot and therefore copy & paste is so much easier with textfiles.

It the same when building a new system. typically you add i.e. a bunch of thermostates, switches, sensors.

A templating funktion would be nice in the ui.Maybe it is an Idea that it is possible to select items groups to beexported. Them you have a template of an item. With a texteditor you could duplicate and adapt it and the import it to the ui

There is no need to have all the information for 1 item in one line.

Dimmer          zWaveLightSwitchDimmer1Wohnzimmer
                       "Dimmer [%d]"
                       <slider>
                       (gPersist,gOffSimulationLichtWohnzimmer)
                       {channel="zwave:device:5001237820:node17:switch_dimmer1"}

yes of course, I know, but I like it more compact on one line but his might change when I added all necessary metadata information to the items

Depending on what you are changing, this can be done in seconds through the REST API docs or editing the JSONDB file directly. I’m not denigrating your script which is quite nice, just pointing out that pointing and clicking through MainUI is not the only option for making changes to the config.

Just be aware that if you change the name of an Item in this way it will generate a duplicate Item with the new name. You’ll still have to delete the old one manually.

If these are all linked to Things then I find “Create Equipment from Thing” to be just about as fast as I ever was with text files. But indeed, if you try to create each Item one by one it would be a pain.

There are a couple of other things worth mentioning. The Links and the metadata are stored separately from the Item in the JSONDB. So it is possible to define the Items up to but not including the { } part in a .items file and then set the metadata and links through the UI, if that approach works best for you.

Also if you are defining default widgets, create a custom widget (under developer tools) and then reuse that on your Items. That way the actual widget config is handled on one place and you don’t have to redo it (copy and paste) for each and every similar Item.

Again, I’m not arguing against this script. I’m just trying to point out that there are approaches to creating and managing Items through the UI that make it so you don’t have to click/edit through MainUI.

tl;dr for the techniques:

  • Use the import from text file way to create and edit your Items. You can create your one liner and copy/paste/edit it right there in the form to make a similar change to lots of similar Items.
  • Use the REST API Docs to query for an Item, edit the JSON with your changes, and push it back to update the Item. Repeat for each similar Item.
  • Stop openHAB and modify the JSONDB manually (I suggest this only if you are trying to change the name of an Item). Make sure you change the name everywhere in all the .jsondb files.
  • Make use of the “Create Equipment from Thing” and “Create Points from Thing” to create all the Items linked to one Thing in one go.
4 Likes

wow thx for all the infos
I didn’t thought of the REST API trick to change things, hmm interesting

By the way, as I tried to figure out how to build my script I found some strange tings in the org.openhab.core.thing.link.ItemChannelLink.json file.

I found two Things with the same content but different IDs but only one is visible in the Things page.
How is this possible and how does OpenHab decided which Thing it reads and does use it?

This one is displayed in the Things Tab in the Settings.

"SqueezeEvita_Power -\u003e squeezebox:squeezeboxplayer:myServer:7aa937d0a974:power": {
    "class": "org.openhab.core.thing.link.ItemChannelLink",

This one is apparently not used anymore but why is it still there and is not removed?

"SqueezeEvita_Power -\u003e squeezebox:squeezeboxplayer:myServer:evita:power": {
    "class": "org.openhab.core.thing.link.ItemChannelLink",

How can I “clean” the file so that only one entry is displayed and used? Does OpenHAB has such a “cleaning” feature?

Andy

I couldn’t say. I’ve not heard of such a thing before now. You should be able to tell which one it’s showing at any given time.

Those are not Things. Those are Links. At least one side of the link appears to be orphaned. Does the Item side still exist? Based on what you’ve said the Thing no longer exists.

I recommend removing it using the REST API Docs. There is a delete link rest API call, but you’ll also need the name of the Item which should be part of the full record. You’ve only shown a couple of lines.

1 Like

here is the full link thing.
The only difference is the name “evita” vs “7aa937d0a974”
One of them is currently active ant its the one with the number (7aa937d0a974)

  "SqueezeEvita_Power -\u003e squeezebox:squeezeboxplayer:myServer:evita:power": {
    "class": "org.openhab.core.thing.link.ItemChannelLink",
    "value": {
      "channelUID": {
        "segments": [
          "squeezebox",
          "squeezeboxplayer",
          "myServer",
          "evita",
          "power"
        ],
        "uid": "squeezebox:squeezeboxplayer:myServer:evita:power"
      },
      "configuration": {
        "properties": {}
      },
      "itemName": "SqueezeEvita_Power"
    }
  }
  "SqueezeEvita_Power -\u003e squeezebox:squeezeboxplayer:myServer:7aa937d0a974:power": {
    "class": "org.openhab.core.thing.link.ItemChannelLink",
    "value": {
      "channelUID": {
        "segments": [
          "squeezebox",
          "squeezeboxplayer",
          "myServer",
          "7aa937d0a974",
          "power"
        ],
        "uid": "squeezebox:squeezeboxplayer:myServer:7aa937d0a974:power"
      },
      "configuration": {
        "properties": {}
      },
      "itemName": "SqueezeEvita_Power"
    }
  }

In the org.openhab.core.thing.Thing.json file there is only one thing:

"squeezebox:squeezeboxplayer:myServer:7aa937d0a974": {

So openhab first looks into the thing file determines the name and searches in the org.openhab.core.thing.link.ItemChannelLink.json file for the corresponding link.

Navigate to the Item in Settings -> Items. Does the orphaned Link appear there? If so click on it and then delete.

If not, open the REST API Docs and go to the Links section and fill out the ID and Item name for the Link you want to delete and delete it from there.

the following may be of interest in this context:

Yes you’re right there was an orphane link thx for the tip

That would be a really nice feature totally support this, best of two worlds!

1 Like

Hi!
I had the same issue as you @AndreasK .

Unfortunatelly the script failed. So I’ve updated it.

Find my changelog and feel free to edit it into yours:

  • Line 129,131,133,…,151: added “strt([…])” on “dataMeta[pMeta][…]” (Not a complete fix, but only for ListWidget / Other dataMeta acesses might be affected too by possible error
  • Line 173: Encoding issue. “line.split(” ", 1)[1] → “line.split(” “, 1)[1].encode(‘utf-8’).strip()”
1 Like

For the uninitiated, would you mind uploading the fully corrected code, please?

E.g. when I look at line 173, it says f.close().

E.g. adding .encode(‘utf-8’).strip() to line 172 leads to:
image

@Max_G You were completely right. I’ve also added a print(.)-line as a debug information - not as part of the solution. But this shifted my lines.

So, no I’ve added also 2 author lines.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Code by AndreasK (openhab.org-User) ~ 2022-02-17
# Modified by ornostar (openhab.org-user) ~ 2022-12-26

import json

print("pls wait...")

exportStr = []
with open('org.openhab.core.items.Item.json') as json_file:
	data = json.load(json_file)
	
	for p in data:				
		# itemType
		itemType = (data[p]['value']['itemType'] + " ") 
		
		# name
		name = str(p)
	
		# label
		label = ""
		if 'label' not in data[p]['value']:
			label = (" \"" + name + "\"")
		else:			
			label = (" \"" + data[p]['value']['label'] + "\"")
			
		# category
		category = ""
		if 'category' in data[p]['value']:		
			category = data[p]['value']['category']
			if category:
				category = (" <" + category + ">")
		
		# groupNames
		groupNames = ""
		if 'groupNames' in data[p]['value']:			
			groupNames = ""
			for erg in data[p]['value']['groupNames']:
				groupNames = groupNames + erg + ", "
			if groupNames:
				groupNames = (" (" + groupNames.rstrip(', ') + ")")
		
		# tags
		tags = ""
		if 'tags' in data[p]['value']:			
			tags = ""
			for ergTags in data[p]['value']['tags']:
				tags = tags + "\"" + ergTags + "\", "
			if tags:
				tags = (" [" + tags.rstrip(', ') + "]")
					
		
		
		# ItemChannelLink
		channel = ""
		uid = ""
		with open('org.openhab.core.thing.link.ItemChannelLink.json') as json_file_links:
			dataLinks = json.load(json_file_links)		
			# print(dataLinks)
			for pLinks in dataLinks:
				if name == dataLinks[pLinks]['value']['itemName']:
					uid = dataLinks[pLinks]['value']['channelUID']['uid']
					with open('org.openhab.core.thing.Thing.json') as json_file_things:
						dataThings = json.load(json_file_things)		
						# print(dataThings)
						for pThings in dataThings:
							if pThings in uid:
								channel = uid
								
		# Metadata
		metadata = ""
		stateDescription = ""
		expire = ""
		widget = ""
		cellWidget = ""
		autoupdate = ""
		listWidget = ""
		
		with open('org.openhab.core.items.Metadata.json') as json_file_meta:
			dataMeta = json.load(json_file_meta)		
			# print(dataMeta)
			for pMeta in dataMeta:
				if name in pMeta:
					if "stateDescription:" in pMeta:
						stateDescription = "stateDescription=\"\"["
						if 'pattern' in dataMeta[pMeta]['value']['configuration']:
							stateDescription = stateDescription + "pattern=\"" + dataMeta[pMeta]['value']['configuration']['pattern'] + "\", "
						if 'min' in dataMeta[pMeta]['value']['configuration']:
							stateDescription = stateDescription + "min=\"" + dataMeta[pMeta]['value']['configuration']['min'] + "\", "
						if 'max' in dataMeta[pMeta]['value']['configuration']:
							stateDescription = stateDescription + "max=\"" + dataMeta[pMeta]['value']['configuration']['max'] + "\", "
						if 'step' in dataMeta[pMeta]['value']['configuration']:
							stateDescription = stateDescription + "step=\"" + dataMeta[pMeta]['value']['configuration']['step'] + "\", "
						if 'options' in dataMeta[pMeta]['value']['configuration']:							
							stateDescription = stateDescription + "options=\"" + dataMeta[pMeta]['value']['configuration']['options'] + "\", "
						stateDescription = stateDescription.rstrip(", ") + "], "
						# print(stateDescription)
					
					if "expire:" in pMeta:
						expire = "expire=\""
						if 'value' in dataMeta[pMeta]['value']:
							expire = expire + dataMeta[pMeta]['value']['value']					
						expire = expire + "\", "
						# print(expire)
						
					if "widget:" in pMeta:
						widget = "expire=\""
						if 'value' in dataMeta[pMeta]['value']:
							widget = widget + dataMeta[pMeta]['value']['value']
						widget = widget + "\", "
						# print(widget)
						
					if "cellWidget:" in pMeta:
						cellWidget = "cellWidget=\""
						if 'value' in dataMeta[pMeta]['value']:
							cellWidget = cellWidget + dataMeta[pMeta]['value']['value']
						cellWidget = cellWidget + "\", "
						# print(cellWidget)
						
					if "autoupdate:" in pMeta:
						autoupdate = "autoupdate=\""
						if 'value' in dataMeta[pMeta]['value']:
							autoupdate = autoupdate + dataMeta[pMeta]['value']['value']
						autoupdate = autoupdate + "\", "
						# print(autoupdate)
					
					if "listWidget:" in pMeta:
						listWidget = "listWidget=\"" + dataMeta[pMeta]['value']['value'] + "\"["
						if 'title' in dataMeta[pMeta]['value']['configuration']:
							listWidget = listWidget + "title=\"" + str(dataMeta[pMeta]['value']['configuration']['title']) + "\", "
						if 'subtitle' in dataMeta[pMeta]['value']['configuration']:
							listWidget = listWidget + "subtitle=\"" + str(dataMeta[pMeta]['value']['configuration']['subtitle']) + "\", "
						if 'icon' in dataMeta[pMeta]['value']['configuration']:
							listWidget = listWidget + "icon=\"" + str(dataMeta[pMeta]['value']['configuration']['icon']) + "\", "
						if 'min' in dataMeta[pMeta]['value']['configuration']:
							listWidget = listWidget + "min=\"" + str(dataMeta[pMeta]['value']['configuration']['min']) + "\", "
						if 'max' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "max=\"" + str(dataMeta[pMeta]['value']['configuration']['max']) + "\", "
						if 'step' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "step=\"" + str(dataMeta[pMeta]['value']['configuration']['step']) + "\", "
						if 'vertical' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "vertical=\"" + str(dataMeta[pMeta]['value']['configuration']['vertical']) + "\", "
						if 'label' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "label=\"" + str(dataMeta[pMeta]['value']['configuration']['label']) + "\", "
						if 'scale' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "scale=\"" + str(dataMeta[pMeta]['value']['configuration']['scale']) + "\", "
						if 'scaleSteps' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "scaleSteps=\"" + str(dataMeta[pMeta]['value']['configuration']['scaleSteps']) + "\", "
						if 'scaleSubSteps' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "scaleSubSteps=\"" + str(dataMeta[pMeta]['value']['configuration']['scaleSubSteps']) + "\", "
						if 'unit' in dataMeta[pMeta]['value']['configuration']:							
							listWidget = listWidget + "unit=\"" + str(dataMeta[pMeta]['value']['configuration']['unit']) + "\", "						
						listWidget = listWidget.rstrip(", ") + "], "
						# print(listWidget)
					
			metadata = (stateDescription + expire + widget + listWidget + cellWidget + autoupdate).rstrip(", ")
		
		
		lastEnt = ""
		if channel:
			lastEnt = "channel=\"" + channel + "\", "
		if metadata:
			lastEnt = lastEnt + metadata + ", "
		if lastEnt:
			lastEnt = (" { " + lastEnt.rstrip(", ") + " }")
				
		exportStr.append(channel + " " + itemType + name + label + category + groupNames + tags + lastEnt)			


# export all the data to a file and sort it 
f = open("export.items", "w")
for line in sorted(exportStr):
	# print (line.split(" ", 1)[1] + "\n")
	f.write(line.split(" ", 1)[1].encode('utf-8').strip() + "\n")
	#f.write(line.split(" ", 1)[1] + "\n")
f.close()

			
print("done")

3 Likes

Running the script (JSON files from openHAB 3.4.1 release) , I get the following error message :

pls wait...
Traceback (most recent call last):
  File "./converter.py", line 63, in <module>
    uid = dataLinks[pLinks]['value']['channelUID']['uid']
KeyError: 'uid'

Already checked for orphaned links and have them purged, no change.
Any clue ?

Hi Hans-Jörg,

I did not wrote the script, but I’ld give it a try to help you.

The error message suggests to have a look into your (item-)thing-channel. So I propose to look into the correspondig file.

You can find it in the backup archive in \userdata\jsondb and its named org.openhab.core.thing.link.ItemChannelLink.json.

Having this file opened you should have a look (or post it here) on each tag that is identical to uid.
Or probably a better approach: check each JSON Object in this file whether is has the uid tag. each objects starts withing the first brackets with a string, like:

{ // first bracket
 "<the objects name>" : { // that is the opening bracket for the object within this object the tag uid is needed.

Example from my configuration:

// the example is from within the object (level) I've described above
      "channelUID": { // this seems to be identical to the concatenated string "uid". So
        "segments": [
          "openweathermap",
          "onecall",
          "72a5b910c5",
          "local",
          "forecastDay2#max-temperature"
        ],
        "uid": "openweathermap:onecall:72a5b910c5:local:forecastDay2#max-temperature" // this is the needed tag I've asked for.
      },
      "configuration": {

Best regards.

Thanks @ornostar ,

adding some print statements I can see the missing uid entries in the JSON file.

As said, I have removed orphaned links via console, so wondering, why those entries are missing in the file.

EDIT : After readding the missing uid’s, the script run through. Only other change I had to make was switching the write command at the end of the script.

Just for information if not known already:
There is a command in REST API to remove all orphaned links at once.
It’s the last one under “links” (a POST-command, not DELETE).
You can do the same with the karaf console:

openhab:links orphan purge

or to only list your orphaned links

openhab:links orphan list
2 Likes

Hi and thanks for this script!

I tried it out, but i get the following error:

pls wait...
Traceback (most recent call last):
  File "export_items", line 175, in <module>
    f.write(line.split(" ", 1)[1].encode('utf-8').strip() + "\n")
TypeError: can't concat str to bytes

The export.items was created, but is empty.

Would be great, if someone could help to handle this.

Thanks,
Alex

see my post earlier