Class Items

This class implements the following methods and properties:

class lib.item.Items(smarthome)[Quellcode]

Bases: object

Items loader class. (Item-methods from bin/smarthome.py are moved here.)

  • An instance is created during initialization by bin/smarthome.py

  • There should be only one instance of this class. So: Don’t create another instance

Parameter:

smarthome (object) – Instance of the smarthome master-object

plugin_attributes = {}
plugin_attribute_prefixes = {}
plugin_prefixes_tuple = None
structs = None
static get_instance()[Quellcode]

Returns the instance of the Items class, to be used to access the items-api

Use it the following way to access the api:

from lib.item import Items

items = Items.get_instance()

# to access a method (eg. return_items()):
items.return_items()
Rückgabe:

items instance

Rückgabetyp:

object

add_struct_definition(plugin_name, struct_name, struct, from_dir='plugins', optional=False)[Quellcode]
return_struct_definitions(all=True)[Quellcode]

Return all loaded structure template definitions

Rückgabe:

Rückgabetyp:

dict

load_itemdefinitions(env_dir, items_dir, etc_dir, plugins_dir)[Quellcode]

Load item definitions

This method is called during initialization of SmartHomeNG to initialize the item tree. For that, it loads the item definitions from ../items directory through calling the function parse_itemsdir() from lib.config

Parameter:
  • env_dir (str) – path to the directory containing the core’s environment item definition files

  • items_dir (str) – path to the directory containing the user’s item definition files

  • etc_dir (str) – path to the directory containing the user’s configuration files (only used for ‚struct‘ support)

  • plugins_dir (str) – path to the directory containing the plugins (only used for ‚struct‘ support)

create_item(path, config, parent=None, persist=True, filename=None, create_missing_parents=False)[Quellcode]

Create a single item at runtime and fully initialize it (and any nested child items declared in config).

Unlike load_itemdefinitions(), which batches the init phases across the whole tree (to support forward references between items being loaded together), this runs the init phases immediately, scoped to only the newly created item and its descendants. A pre-existing item with a wildcard trigger: pattern that would now match this new item is not retroactively rewired — that would require re-running _init_prerun() across the whole tree on every creation.

If parent is not given and path has a dotted parent segment, that parent is resolved by path. A missing parent raises ValueError unless create_missing_parents is set, in which case every missing ancestor is created first (in order, shallow to deep) as an empty item — same as calling create_item() on each of them individually with an empty config.

Parameter:
  • path (str) – Full path of the item to create

  • config (dict) – Attribute configuration dict for the item

  • parent – Item under which to create this item; None to resolve the parent from path (or for a top-level item, if path has no dot)

  • persist (bool) – If True (default), also write config to a yaml file in items_dir, so the item survives a restart. If False, the item is runtime-only, same as before this parameter existed.

  • filename (str) – Basename (without extension) of the yaml file to persist to. Only used when persist is True; falls back to sh._created_items_file if not given. Auto-created missing parents use the same persist/filename as path itself.

  • create_missing_parents (bool) – If True, auto-create any missing ancestor of path (as an empty item) instead of raising ValueError.

Rückgabe:

The newly created Item, or None if its own name collided with an existing attribute and was dropped — see lib.item._internal._parsing.check_item_name_collision(). A collision on an auto-created ancestor instead raises ValueError, since silently dropping just an ancestor would leave the requested item never created but reported as if the failure were about path itself.

Rückgabetyp:

Item or None

add_item(path, item)[Quellcode]

Function to to add an item to the dictionary of items. If the path does not exist, it is created

Parameter:
  • path (str) – Path of the item

  • item (object) – The item itself

edit_item(item, config)[Quellcode]

Edit an existing item’s attributes at runtime, in place — preserves Python object identity (unlike create_item()/remove_item()), so other items‘ incoming trigger/hysteresis_input registrations onto item, and this item’s own value/history/children, all survive automatically without any rewiring step. See ~/.claude/handoff/shng-edit-item-attributes.md for the full design rationale.

config is the COMPLETE new attribute set, same convention as create_item() — omitting a key resets it to its default, there is no separate partial-patch/delete-sentinel scheme.

Other items‘ incoming trigger/hysteresis_input registrations onto item live on THIS item’s own _items_to_trigger list, which an edit never resets — they survive an edit untouched, with no special-case code needed here.

Parameter:
  • item (object) – The item to edit

  • config (dict) – Complete new attribute configuration dict

Rückgabe:

The same item, mutated

Rückgabetyp:

Item

remove_item(item, persist=True, recursive=False)[Quellcode]

Function to remove an item from the dictionary of items and delete the item object.

An item with sub-items is left untouched (raises ValueError) unless recursive is set — sub-items are not necessarily defined in the same yaml file as their parent (each item tracks its own _filename independently), so this can’t be handled as a side effect of removing the parent’s own yaml node; every descendant is removed individually, deepest first, each via its own source file.

Parameter:
  • item (object) – The item to delete

  • persist (bool) – If True (default), also remove the item’s entry from the yaml file it was defined in (item. property.defined_in/item._filename), if any. Works for any item with a known source file, not only ones created via create_item(persist=True) — deliberately generic. No-op if the item has no known source file. Applies to every removed descendant too, each using its own source file.

  • recursive (bool) – If True, also remove every sub-item first (deepest first). If False (default) and item has sub-items, raises ValueError instead of removing anything.

rename_item(item, new_path, filename=None)[Quellcode]

Rename an item in place, optionally moving it to a new parent (see ~/.claude/handoff/shng-rename-item-design.md). Mutates the item’s own path (and, for a move, its parent) and re-keys it in __item_dict; unlike edit_item(), the item’s attribute config is untouched, only its identity (path/parent).

If the item is persisted, its YAML node moves to: filename if given explicitly; otherwise the new parent’s file, if the new parent is a real (non-top-level) Item with one; otherwise the item’s own current file unchanged (same-file rename, the original v1 behavior). A non-persisted item is never persisted as a side effect of a move.

Parameter:
  • item – The item to rename/move

  • new_path (str) – The item’s new full path — same parent segment for a plain rename, a different one to move it

  • filename (str) – Explicit target yaml file (basename, no extension) to override the default above

Rückgabe:

The same item, mutated

Rückgabetyp:

Item

copy_item(item, new_path, filename=None, create_missing_parents=False, include_children=True)[Quellcode]

Copy an item to new_path as an independent clone — fresh plugin bindings and value history, no shared identity with the source (unlike rename_item(), which preserves identity and only relocates it). Copies the item’s entire subtree by default; set include_children to False to copy only the item itself.

Only persisted items can be copied: there is no existing helper that reconstructs a full nested (with-children) config dict from a live, non-persisted item tree — current_config_for_edit() strips child (dict-valued) keys on purpose, since edit_item() never touches children. A non-persisted source raises ValueError.

The copy is written to filename if given, otherwise to the SOURCE item’s own file — deliberately not the new parent’s file the way rename_item() defaults when moving, since a copy is meant to be „the same config, elsewhere,“ not adopt its new neighbourhood’s file.

Self-references inside the copied subtree (eval/on_change/ on_update/trigger/hysteresis_input/cycle/autotimer/ hysteresis_upper_threshold/hysteresis_lower_threshold) are handled differently depending on whether their target is actually part of what’s being copied:

  • An absolute (sh.<path>/bare-path) reference whose target IS part of the copy (old_path itself, or one of its descendants when include_children brought it along) is rewritten from old_path to new_path, via the same boundary-aware prefix replace rename_item() uses for external references.

  • An absolute reference whose target is NOT part of the copy (a descendant include_children=False left behind, or something entirely outside old_path’s subtree) is left pointing at the original — reported back in left_pointing_at_original rather than silently rewritten to a path that won’t exist, or silently dropped.

  • A relative reference (leading-dot syntax, resolved fresh against the item’s own position at every load) is NEVER rewritten — its target is inherently tied to tree position, so „leaving it alone“ IS the text staying byte-for-byte the same. It’s classified instead: silently fine if it still resolves inside the copied tree; always reported in relative_references_flagged if its original target was a descendant that wasn’t copied along (guaranteed broken); and, if its target was outside old_path’s subtree entirely, reported only if re-resolving the same text from the new position lands on a different target than before (can’t tell whether that drift is a bug or intentional, so it’s surfaced rather than guessed at).

Parameter:
  • item – The item to copy

  • new_path (str) – Full path for the copy

  • filename (str) – Explicit target yaml file (basename, no extension) to override the default (source item’s own file)

  • create_missing_parents (bool) – If True, auto-create any missing ancestor of new_path instead of raising ValueError — see create_item().

  • include_children (bool) – If False, copy only the item’s own attributes — none of its child items.

Rückgabe:

(copy, report) — copy is the newly created copy, or None if its own name collided with an existing attribute and was dropped (see create_item()); report is {„left_pointing_at_original“: […], „relative_references_flagged“: […]}, each entry a dict with item/attribute/reference (plus a reason and the resolved old/new targets for relative entries) — see _rewrite_subtree_self_references().

Rückgabetyp:

tuple(Item or None, dict)

find_references(path)[Quellcode]

Best-effort search for textual references to item path inside other items‘ eval, on_change, on_update, trigger and hysteresis_input attributes.

This is a review aid, not a safety mechanism: a reference embedded in free-form eval text cannot be tracked structurally (unlike trigger/hysteresis_input, which already are, via _items_to_trigger/_hysteresis_items_to_trigger — those are included here too, for a complete picture in one place). There is no guarantee of completeness (e.g. a computed/concatenated reference won’t be found) and no guarantee against false positives beyond a word-boundary match. Intended to be called interactively before deleting an item, so a human can review the result — it is deliberately not wired into remove_item() itself.

Parameter:

path (str) – Path of the item to search for

Rückgabe:

List of (item, attribute_name, attribute_value, unambiguous) tuples, one per match. unambiguous is True if path is the only item the matched text depends on (see _is_unambiguous_reference()) — a hint for which matches might be safe to auto-clean later, not a guarantee.

Rückgabetyp:

list

current_config_for_edit(item)[Quellcode]

Best-effort reconstruction of item’s current complete attribute config, suitable as a base for an edit_item() call — there is no single source of truth for this on a live Item (core attributes like eval/trigger/type live in dedicated fields, not item.conf, see Item._apply_config()).

If item is persisted, its on-disk YAML entry IS that complete config (exactly what create_item()/edit_item() last wrote there) — used directly, with any child-item blocks (dict-valued keys) stripped, since edit_item() handles children separately. If not persisted, falls back to reading the known core fields plus item.conf — accurate for every attribute find_references() can detect, but may not preserve more obscure attributes that were never written to a config dict in the first place.

Used internally by remove_references()/rename_item() to build a referencing item’s new config, and exposed cross-module (e.g. via modules/admin/itemdata.py’s „editable_config“ field) so a frontend can safely pre-populate an edit-attributes form — item.conf alone (the „config“ field there) never includes core attributes, only generic/plugin ones, so it’s unsafe to PATCH back as-is.

Parameter:

item – The item to read the current config for

Rückgabe:

Attribute configuration dict

Rückgabetyp:

dict

remove_references(path)[Quellcode]

Strip dangling unambiguous references to path from every other item, via find_references()/edit_item() — intended to be called right before deleting the item at path, so other items aren’t left pointing at something that no longer exists.

Ambiguous references (something else the referencing attribute also depends on) are left untouched and reported back, not treated as an error — there is no safe automatic action for them.

trigger/hysteresis_input matches are mechanical (the whole matched value IS the bare path) — the trigger list entry is filtered out (dropping the key if the list becomes empty), or hysteresis_input is cleared. eval is a single freeform expression — the entire attribute is cleared, since a substring can’t be safely excised from arbitrary Python. on_change/ on_update are lists of independent freeform expressions, like trigger structurally — only the matching list entry is dropped, the rest of the list survives.

A referencing item with multiple dangling attributes (e.g. both eval and trigger pointing at path) gets ONE edit_item() call with all of its changes combined, not one call per attribute.

Parameter:

path (str) – Path of the item whose incoming references should be cleaned up

Rückgabe:

{„removed“: [(item_path, [attribute_names])], „skipped_ambiguous“: [(item_path, attribute_name, value)]}

Rückgabetyp:

dict

get_toplevel_items()[Quellcode]

Returns a list with all items defined at the top level

Rückgabe:

items defined at the top level

Rückgabetyp:

list

return_item(string)[Quellcode]

Function to return the item for a given path

Parameter:

string (str) – Path of the item to return

Rückgabe:

Item

Rückgabetyp:

object

return_items(ordered=False)[Quellcode]

Function to return a list with all defined items

Parameter:

ordered (bool) – return list sorted alphabetically, defaults to False

Rückgabe:

List of all items

Rückgabetyp:

list

match_items(regex)[Quellcode]

Function to match items against a regular expression

Parameter:

regex (str) – Regular expression to match items against

Rückgabe:

List of matching items

Rückgabetyp:

list

find_items(conf)[Quellcode]

Function to find items that match the specified configuration

Parameter:

conf (str) – Configuration to look for

Rückgabe:

list of matching items

Rückgabetyp:

list

find_children(parent, conf)[Quellcode]

Function to find children with the specified configuration

Parameter:
  • parent (str) – parent item on which to start the search

  • conf (str) – Configuration to look for

Rückgabe:

list or matching child-items

Rückgabetyp:

list

item_count()[Quellcode]

Return the number of defined items

Rückgabe:

number of items

Rückgabetyp:

int

stop(signum=None, frame=None)[Quellcode]

Stop what all items are doing

At the moment, it stops fading of all items

add_plugin_attribute(plugin_name, attribute_name, attribute)[Quellcode]

Add an attribute definition to the dict of plugin specific item-attributes

Parameter:
  • plugin_name – Name of the plugin that defines the attribute

  • attribute_name – Name of the attribute

  • attribute – Metadata that defines the attribute

Rückgabe:

add_plugin_attribute_prefix(plugin_name, prefix_name, prefix)[Quellcode]

Add an attribute-prefix definition to the dict of plugin specific item-attribute prefixes

Parameter:
  • plugin_name – Name of the plugin that defines the attribute

  • prefix_name – Name of the attribute-prefix

  • prefix – Metadata that defines the attribute-prefix

Rückgabe:

plugin_attribute_exists(attribute_name)[Quellcode]

Returns the type of the attribute’s value

Parameter:

attribute_name – Name of the attribute

Rückgabe:

Type of the attribute’s value or None

get_plugin_attribute_type(attribute_name)[Quellcode]

Returns the type of the attribute’s value

Parameter:

attribute_name – Name of the attribute

Rückgabe:

Type of the attribute’s value or None