Writing Standalone Python Scripts

Python can be used to write standalone scripts that you can run from the console.

Starting Proficy Code

To start the Proficy Code editor with the CIMPLICITY Python environment properly set up, you can run the following command from the Windows search box:

%cimpath%\proficy_code_launcher.exe

Proficy Code appears with no CIMPLICITY project context. This means, for example, you must fully qualify point IDs with the project name and any log_status messages will show up in the system log, not in a project log file.

Example:

You can try the following simple script:

  1. Enter the following script into Proficy Code and save the file with a “.py” extension.

    print("hello")

  2. Run the script from the command palette by typing Ctrl+Shift+R, and then start typing Python: Run Python File in Terminal. You can also use the play button in the upper right corner of the window.

  3. Add a simple CIMPLICITY API call. IntelliSense tool appears when you type “cimplicity.” in the last statements.

    import cimplicity
    import os 
    print("hello")
    cimplicity.log_status(cimplicity.StatusSeverity.SUCCESS, 
                          os.path.basename(__file__), "hello")
    cimplicity.terminate_api_in_thread()
  4. Run the code.

    Result: The log message is displayed in the CIMPLICITY system status log.
    Note: When you use the CIMPLICITY API in a thread other than the one Event Manager calls the do_event_action method in, you must call cimplicity.terminate_api_in_thread before the thread exits. (It may not be strictly necessary when only calling cimplicity.log_status.)

More involved script

In the following script we get and set point values.

Notes

  • In the beginning of the script we use the point_get and point_set methods which are useful for quick access to points one time. If you are going to get and/or set a point value multiple times, it is more efficient to use a Point object.
  • You must fully qualify the points as this CIMPLICITY environment is not associated with any project.
  • Do not combine fully qualified and unqualified point references in the same client.
  • A qualified point ID looks like \\proj\pointid. When entering that in a Python string you must escape the backslashes: \\\\proj\\pointid.
  • When you run the script for the first time, CIMPLICITY will prompt you to log into the project.
  • Call cimplicity.terminate_api_in_thread in a finally block to ensure it is always called.
import cimplicity
import os
import time

try:
    print("hello")
    cimplicity.log_status(cimplicity.StatusSeverity.SUCCESS,
                          os.path.basename(__file__), "hello")

    PTVAL = "\\\\SITEA\\AirConditioner_1.Humidity"
    PTVAL_SETPT = "\\\\SITEA\\AirConditioner_1.HumiditySetpoint"

    val = cimplicity.point_get(PTVAL)
    print(f"Current value = {val:.2f}")
    val = cimplicity.point_get(PTVAL_SETPT)
    print(f"Current value_setpoint = {val:.2f}")

    newval = input("-> Enter new value_setpoint: ")
    cimplicity.point_set(PTVAL_SETPT, newval)
    val = cimplicity.point_get(PTVAL_SETPT)
    print(f"Current value_setpoint = {val:.2f}")

    with cimplicity.Point() as pt:
        pt: cimplicity.Point  # this declaration helps IntelliSense
        pt.id = PTVAL
        for i in range(0, 10):  # range(inclusive, exclusive)
            if i > 0:
                time.sleep(1)  # seconds
            print(f"... value = {pt.get_value():.2f}"
                  f" (at {pt.timestamp_local})")
finally:
    cimplicity.terminate_api_in_thread()
Starting Proficy Code in a Project Context
If you want to work on standalone scripts for a particular project:
  1. Open the project in the Workbench
  2. Select the Tools > Command Prompt menu item.
  3. In the command prompt, enter the following command to launch Proficy Code and open the scripts folder. %cimpath%\proficy_code_launcher.exe scripts
    Note: You are recommended to put your standalone scripts in a subdirectory of the scripts directory to keep them separate.
    Note: In the command prompt you can also type “python” and it will run in the CIMPLICITY Python environment.

You can follow the above steps to build up a script, but this time you will not need to use fully qualified point IDs.

import cimplicity
import sys
import time

class EventHandlerState:

    def __init__(self, event_action_context: cimplicity.EMEventActionContext):
        # store the object attributes for later use
        self.obj_attrs = event_action_context.object_attributes
        print(f"__init__: obj_attrs: {self.obj_attrs}")
        sys.stdout.flush()

    def do_event_action(self, event_data: cimplicity.CimEMEvent):
        cimplicity.log_status(
            cimplicity.StatusSeverity.SUCCESS, "myscript", "running")
        print(f"event_id: {event_data.event_id}")
        print(f"action_id: {event_data.action_id}")
        print(f"object_id: {event_data.object_id}")
        print(f"timestamp_local: {event_data.timestamp_local}")
        print(f"event type: {event_data.type}")
        print(f"obj_attrs: {self.obj_attrs}")
        if event_data.point_event is not None:
            print("point event:")
            pe: cimplicity.CimEMPointEvent = event_data.point_event
            print(f"  point ID: {pe.id}")
            print(f"  state: {pe.state}")
            print(f"  quality: {pe.quality}")
            print(f"  timestamp_local: {pe.timestamp_local}")
        sys.stdout.flush()

    def do_shutdown(self, event_data: cimplicity.CimEMEvent):
        pass

def do_test():
    # construct an EventHandlerState object
    ea_ctx = cimplicity.EMEventActionContext(
        "WORKUNIT03.OfflineForMaintEvent", "WORKUNIT03.OfflineForMaintAction",
        "WORKUNIT03", {"A_HASSCANNER": "0", "A_HASBUFFER": "1"})
    eh_state = EventHandlerState(ea_ctx)
    # construct the CimEMEvent and CimEMPointEvent objects
    ts_cimp = time.time_ns() / 100
    quality = (cimplicity.QualityFlags.IS_AVAILABLE
               | cimplicity.QualityFlags.IS_IN_RANGE
               | cimplicity.QualityFlags.ALARMS_ENABLED
               | cimplicity.QualityFlags.ACK_OCCURRED)
    pt_event = cimplicity.CimEMPointEvent(
        "WORKUNIT03.OfflineForMaintPoint", "value", quality, ts_cimp,
        cimplicity.PointState.NORMAL, 0)
    # call the do_event_action method
    eh_state.do_event_action(cimplicity.CimEMEvent(
        cimplicity.EventType.POINT_CHANGE, ea_ctx.object_id,
        ea_ctx.event_id, ea_ctx.action_id, ts_cimp, None, pt_event,
        None))
if __name__ == "__main__":
    do_test()