Simulation

Description

The simulation plugin allows simulating presence in case none is at home. To achieve this, the plugin constantly records all configured items and writes changes to those (events) into a file. It is a text file where each event has one line. The file can be modified using a text editor, but be careful. Upon request the plugin can playback the contents of this file.

Requirements

This plugins has no requirements.

Configuration

plugin.yaml

simulation:
    class_name: Simulation
    class_path: plugins.simulation
    data_file: /usr/smarthome/var/db/simulation.txt
    # callers:
    #   - KNX
    #   - Visu

data_file: This is the file where all recorded events are stored.

callers: Is an optional list of event sources for recording of events. When an item is changed, the change is done by someone, e.g. knx for changes from the bus. The caller name is set by the plugin programmer and has to be found out manually. Only item changes with a caller in the list are recorded to the simulation file. In the example above e.g. uzsu is ignored. Be aware that the caller in the list has to be case sensitive. Otherwise it won‘t trigger.

items.yaml

sim: track

Add sim: track to each item that you want to include in the simulation. All items with with the sim Attribute are tracked in the data_file. Each change of the item is stored as one line. Only bool and number items are supportet.

Example

eg:

    flur:

        licht:
            type: bool
            visu_acl: rw
            knx_dpt: 1
            knx_cache: 1/1/1
            knx_send: 1/1/0
            enforce_updates: 'yes'
            sim: track

Add to your item tree some adminstrative items:

sim:

    status:
        type: num
        sim: state
        visu_acl: ro

    control:
        type: num
        sim: control
        visu_acl: rw

    message:
        type: str
        sim: message
        visu_acl: ro

    tank:
        type: num
        sim: tank
        visu_acl: ro

These items are needed to control the simulation plugin. If they do not exist, the plugin will fail to initialize.

state: is set by the plugin and can be read in order to see which state the plugin is in.

   00: Stop
       The plugin is inactive. It does not record or play anything
   01: Standby
       The plugin does not yet record, but will start at a scheduled time
   02: Record
       The plugin records all configured events
   04: Play
       The plugin plays the event file

control: The control item is set by the user to

   01: Stop
       Setting control to 01 will stop recording or playback
   02: Play
       Setting control to 02 will start playback. If record is running, it will
       be stopped automatically
   03: Record
       Setting control to 03 will start recording. If playback is running, it will
       be stopped automatically

message: The message item is set by the plugin depending in the events. In case of recording it contains the last recorded event. In case of playback it contains the next event. In case of errors, it will contain an error message. Use this in a visualization in order to see what the plugin is doing.

tank: Thank contains the actual value of day that are stored in the events file. The value will grow up to 14 and then stay constant. Put his in the visu in case you want to see if there are already enough events to start a playback.

Usage

Record

The plugin starts automatically together with smarthome.py. After initialization it automatically starts to record all changes to items that have the sim: track in the item.yaml file. Item datatypes bool and num have been tested. When an item is changed it is called an event. All events are stored in a text file. It does not matter where the change is initiated from with one exception: The plugin does not record events that are triggered by the plugin itself when it is in playback mode. When the plugin initializes for the first time, the event file is created. On all subsequent starts events are appended to the existing file. The plugin records a maximum of 14 days. When the 15th day is over, the first day is deleted. So the file always contains the recent 14 days plus the rest of today. When recording starts, either after startup or after setting control to 03, it does not start immediately. In case the event file is empty, recording will start at next midnight. Until midnight the plugin will be in stand-by. By that there will always be a full day in the file. In case the plugin finds events in the file, it compares the last recorded event with the actual time. In case the actual time is max. 15 minutes advance the last recorded event, recording will start immediately. In case the actual time is more advance, recording will start one minute after the last event on the next day. Ba this behavior empty gaps in the event file are avoided when recording was stopped for some time because .eg. playback was active. If control is set to 01, recording stops immediately.

Playback

Setting control to 02 will start playback. Recording will stop automatically. Item changes triggered by the simulation are not recorded. In playback mode, the plugin reads the file line by line and executes the events by changing the item as it was recorded. When the file ends, the simulation stops. The day of the event is ignored. The plugin just plays the time stamps one after the other. In case the next time stamp is before the actual time the plugin shifts the event to the next day.

Control

The plugin needs certain control items to exist. They can be integrated in smartVISU. I created a block the looks like in the following picture:

screenshot

The code is here. Replace the item names with yours from the item.yaml file. The png files for the lamps are in the package.

SmartVisu 2.9:

/** # Simulations Plugin Bedienung ---------------------------------------------------------*/
<div class="block">
	<div class="set-2" data-role="collapsible-set" data-theme="c" data-content-theme="a" data-mini="true">
		<div data-role="collapsible" data-collapsed="false">
		<h3>Anwesenheitssimulation</h3>
		<table width=100%>
			<tr>
				<td>{{ basic.symbol('','sim.status','','lamp_sim.svg',['4','0','1','2','3'],'',['#0b0','#A4A4A4','#A4A4A4','#A4A4A4','#A4A4A4']) }}</td>
				<td>Aufgenommene Tage<br>{{ basic.print('', 'sim.tank') }}</td>
				<td>{{ basic.symbol('','sim.status','','lamp_sim.svg',['0','4','1','2','3'],'',['#A4A4A4','#A4A4A4','#fa3','#f00','#BF00FF']) }}</td>
				<td rowspan=3 width="20%">{{ basic.tank('P_tank1', 'sim.tank',0,15,1,'cylinder','#0C0') }}</td>
			</tr><tr>
				<td>{{ basic.stateswitch('', 'sim.control', 'mini', '2', 'audio_play.svg', '', '') }}</td>
				<td>{{ basic.stateswitch('', 'sim.control', 'mini', '1', 'audio_stop.svg', '', '') }}</td>
				<td>{{ basic.stateswitch('', 'sim.control', 'mini', '3', 'audio_rec.svg', '', '') }}</td>
				<td></td>
			</tr><tr>
				<td colspan=3 width="80%">{{basic.print('','sim.message', 'html') }}</td>
				<td></td>
			</tr>
		</table>
	</div>
  </div>
</div>

SmartVisu <= 2.8:

<h1><img class="icon" src='{{ icon0 }}time_clock.png' />Simulation</h1>
<div class="block">
  <div class="set-2" data-role="collapsible-set" data-theme="c" data-content-theme="a" data-mini="true">
    <div data-role="collapsible" data-collapsed="false">
      <h3>Anwesenheitssimulation</h3>
      <table width=100%>
	<tr>
	  <td>
            {{basic.symbol('P_SIM01','ZF.sim.status','',icon0~'lamp_green.png',4)}}
            {{basic.symbol('P_SIM02','ZF.sim.status','',icon0~'lamp_off.png',0)}}
            {{basic.symbol('P_SIM03','ZF.sim.status','',icon0~'lamp_off.png',1)}}
            {{basic.symbol('P_SIM04','ZF.sim.status','',icon0~'lamp_off.png',2)}}
            {{basic.symbol('P_SIM05','ZF.sim.status','',icon0~'lamp_off.png',3)}}
	  </td>
	  <td>
              Days recorded<br>{{ basic.value('P_SIM_T', 'ZF.sim.tank') }}
	  </td>
	  <td>
            {{basic.symbol('P_SIM06','ZF.sim.status','',icon0~'lamp_off.png',0)}}
            {{basic.symbol('P_SIM07','ZF.sim.status','',icon0~'lamp_off.png',4)}}
            {{basic.symbol('P_SIM08','ZF.sim.status','',icon0~'lamp_orange.png',1)}}
            {{basic.symbol('P_SIM09','ZF.sim.status','',icon0~'lamp_red.png',2)}}
            {{basic.symbol('P_SIM10','ZF.sim.status','',icon0~'lamp_purple.png',3)}}
	  </td>
	  <td rowspan=3 width="20%">
            {{ basic.tank('P_tank1', 'ZF.sim.tank',0,15,1,'cylinder','#0C0') }}
	  </td>
	</tr>
	<tr>
	  <td>
            {{basic.button('P_SIMBTN04','ZF.sim.control','Play','',2) }}
	  </td>
	  <td>
            {{basic.button('P_SIMBTN05','ZF.sim.control','Stop','',1) }}
	  </td>
	  <td>
            {{basic.button('P_SIMBTN06','ZF.sim.control','Rec','',3) }}
	  </td>
	  <td>
	  </td>
	</tr>
	<tr>
          <td colspan=3 width="80%">
            {{basic.value('P_SIMSTAT','ZF.sim.message') }}
	  </td>
	  <td>
	  </td>
	</tr>
      </table>
    </div>
  </div>
</div>

Internals

Event file format

Each event is stored in one line in the following format:

Day;Time;Item;Value;Trigger e.g:

Tue;06:05:27;OG.Tobias.Deckenlicht;True;KNX

At 00:00 the string „NextDay“ is put into one line. The value of Trigger is the source from where the item was changed during record. Day and Trigger are ignored for the time being and might be used later.

State Diagram

The following state diagram shows the state changes depenging on the control item. The state is stored in the state item.

Statediagram