State and Status

State and Status#

All Tango devices automatically provide State and Status information that can be queried at any time.

In the previous lesson you saw that this was just UNKNOWN and 'The device is in UNKNOWN state.' for your first device. You want to make this a little better.

main.py#
from tango import DevState
from tango.server import Device


class MegaCoffee3k(Device):
    def init_device(self):
        super().init_device()
        self.set_state(DevState.OFF)
        self.set_status("Hello world - device is off.")


if __name__ == "__main__":
    MegaCoffee3k.run_server()
MegaCoffee3k.xmi#
<?xml version="1.0" encoding="ASCII"?>
<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://tango.org/pogo/PogoDsl">
  <classes name="MegaCoffee3k" pogoRevision="9.9">
    <description description="" title="Tango MegaCorp Coffee machines 3000 series" sourcePath="/Users/antjou/tango-src/tango-doc/source/tutorial/src/cpp/01" language="Cpp" filestogenerate="XMI   file,Code files,CMakeLists,Protected Regions,WindowsCMakeLists" license="LGPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="false" hasAbstractCommand="false" hasAbstractAttribute="false">
      <inheritances classname="Device_Impl" sourcePath=""/>
      <identification contact="at tango-megacorp.inc - software" author="software" emailDomain="tango-megacorp.inc" classFamily="Training" siteSpecific="" platform="All Platforms" bus="TCP/UDP" manufacturer="Tango MegaCorp" reference=""/>
    </description>
    <commands name="State" description="This command gets the device state (stored in its device_state data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0">
      <argin description="none">
        <type xsi:type="pogoDsl:VoidType"/>
      </argin>
      <argout description="Device state">
        <type xsi:type="pogoDsl:StateType"/>
      </argout>
      <status abstract="true" inherited="true" concrete="true"/>
    </commands>
    <commands name="Status" description="This command gets the device status (stored in its device_status data member) and returns it to the caller." execMethod="dev_status" displayLevel="OPERATOR" polledPeriod="0">
      <argin description="none">
        <type xsi:type="pogoDsl:VoidType"/>
      </argin>
      <argout description="Device status">
        <type xsi:type="pogoDsl:ConstStringType"/>
      </argout>
      <status abstract="true" inherited="true" concrete="true"/>
    </commands>
    <preferences docHome="./doc_html" makefileHome="/opt/homebrew/Caskroom/mambaforge/base/envs/pogo/share/pogo/preferences"/>
  </classes>
</pogoDsl:PogoSystem>
main.cpp#
/*----- PROTECTED REGION ID(MegaCoffee3k::main.cpp) ENABLED START -----*/
/* clang-format on */
//=============================================================================
//
// file :        main.cpp
//
// description : C++ source for the MegaCoffee3k device server main.
//               The main rule is to initialize (and create) the Tango
//               system and to create the DServerClass singleton.
//               The main should be the same for every Tango device server.
//
// project :     Tango MegaCorp Coffee machines 3000 series
//
// This file is part of Tango device class.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================
#include <tango/tango.h>

// Check if crash reporting is used.
#if defined(ENABLE_CRASH_REPORT)
#  include <crashreporting/crash_report.h>
#else
#  define DECLARE_CRASH_HANDLER
#  define INSTALL_CRASH_HANDLER
#endif

DECLARE_CRASH_HANDLER

int main(int argc,char *argv[])
{
	INSTALL_CRASH_HANDLER
	Tango::Util *tg = nullptr;
	try
	{
		// Initialize the device server
		//----------------------------------------
		tg = Tango::Util::init(argc,argv);

		// Create the device server singleton
		//	which will create everything
		//----------------------------------------
		tg->server_init(false);

		// Run the endless loop
		//----------------------------------------
		std::cout << "Ready to accept request" << std::endl;
		tg->server_run();
	}
	catch (std::bad_alloc &)
	{
		std::cout << "Can't allocate memory to store device object !!!" << std::endl;
		std::cout << "Exiting" << std::endl;
	}
	catch (CORBA::Exception &e)
	{
		Tango::Except::print_exception(e);

		std::cout << "Received a CORBA_Exception" << std::endl;
		std::cout << "Exiting" << std::endl;
	}

	if(tg)
	{
		tg->server_cleanup();
	}
	return(0);
}

/* clang-format off */
/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k::main.cpp
MegaCoffee3kClass.h#

MegaCoffee3kClass.cpp#

MegaCoffee3k.h#

MegaCoffee3k.cpp#

MegaCoffee3kStateMachine.cpp#

CMakeLists.txt#

MegaCoffee3k.xmi#
<?xml version="1.0" encoding="ASCII"?>
<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://tango.org/pogo/PogoDsl">
  <classes name="MegaCoffee3k" pogoRevision="9.9">
    <description description="" title="Tango MegaCorp Coffee machines 3000 series" sourcePath="/Users/antjou/tango-src/tango-doc/source/tutorial/src/java/01" language="Java" filestogenerate="XMI   file,Code files,Makefile,Protected Regions,pom.xml" license="LGPL" copyright="" hasMandatoryProperty="false" hasConcreteProperty="false" hasAbstractCommand="false" hasAbstractAttribute="false">
      <inheritances classname="Device_Impl" sourcePath=""/>
      <identification contact="at tango-megacorp.inc - software" author="software" emailDomain="tango-megacorp.inc" classFamily="Training" siteSpecific="" platform="All Platforms" bus="TCP/UDP" manufacturer="Tango MegaCorp" reference=""/>
    </description>
    <commands name="State" description="This command gets the device state (stored in its device_state data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0">
      <argin description="none">
        <type xsi:type="pogoDsl:VoidType"/>
      </argin>
      <argout description="Device state">
        <type xsi:type="pogoDsl:StateType"/>
      </argout>
      <status abstract="true" inherited="true" concrete="true"/>
    </commands>
    <commands name="Status" description="This command gets the device status (stored in its device_status data member) and returns it to the caller." execMethod="dev_status" displayLevel="OPERATOR" polledPeriod="0">
      <argin description="none">
        <type xsi:type="pogoDsl:VoidType"/>
      </argin>
      <argout description="Device status">
        <type xsi:type="pogoDsl:ConstStringType"/>
      </argout>
      <status abstract="true" inherited="true" concrete="true"/>
    </commands>
    <preferences docHome="./doc_html" makefileHome="/opt/homebrew/Caskroom/mambaforge/base/envs/pogo/share/pogo/preferences"/>
  </classes>
</pogoDsl:PogoSystem>
MegaCoffee3k.java#
/*----- PROTECTED REGION ID(MegaCoffee3k.java) ENABLED START -----*/
//=============================================================================
//
// file :        MegaCoffee3k.java
//
// description : Java source for the MegaCoffee3k class and its commands.
//               The class is derived from Device. It represents the
//               CORBA servant object which will be accessed from the
//               network. All commands which can be executed on the
//               MegaCoffee3k are implemented in this file.
//
// project :     Tango MegaCorp Coffee machines 3000 series
//
// This file is part of Tango device class.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================

/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.java

package org.tango.megacoffee3k;

/*----- PROTECTED REGION ID(MegaCoffee3k.imports) ENABLED START -----*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import org.tango.DeviceState;
import org.tango.server.InvocationContext;
import org.tango.server.ServerManager;
import org.tango.server.annotation.AroundInvoke;
import org.tango.server.annotation.Attribute;
import org.tango.server.annotation.AttributeProperties;
import org.tango.server.annotation.ClassProperty;
import org.tango.server.annotation.Command;
import org.tango.server.annotation.Delete;
import org.tango.server.annotation.Device;
import org.tango.server.annotation.DeviceProperty;
import org.tango.server.annotation.DynamicManagement;
import org.tango.server.annotation.Init;
import org.tango.server.annotation.State;
import org.tango.server.annotation.StateMachine;
import org.tango.server.annotation.Status;
import org.tango.server.annotation.DeviceManagement;
import org.tango.server.annotation.Pipe;
import org.tango.server.attribute.ForwardedAttribute;import org.tango.server.pipe.PipeValue;
import org.tango.server.dynamic.DynamicManager;
import org.tango.server.device.DeviceManager;
import org.tango.server.dynamic.DynamicManager;
import org.tango.server.events.EventManager;
import org.tango.server.events.EventType;
import org.tango.utils.DevFailedUtils;

//	Import Tango IDL types
import fr.esrf.Tango.*;
import fr.esrf.TangoDs.Except;
import fr.esrf.TangoApi.PipeBlob;
import fr.esrf.TangoApi.PipeDataElement;

/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.imports

/**
 *  MegaCoffee3k class description:
 *
 */

@Device
public class MegaCoffee3k {

	protected static final Logger logger = LoggerFactory.getLogger(MegaCoffee3k.class);
	protected static final XLogger xlogger = XLoggerFactory.getXLogger(MegaCoffee3k.class);
	//========================================================
	//	Programmer's data members
	//========================================================
    /*----- PROTECTED REGION ID(MegaCoffee3k.variables) ENABLED START -----*/

    //	Put static variables here

    /*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.variables
	/*----- PROTECTED REGION ID(MegaCoffee3k.private) ENABLED START -----*/

	//	Put private variables here

	/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.private

	//========================================================
	//	Property data members and related methods
	//========================================================


	//========================================================
	//	Miscellaneous methods
	//========================================================
	/**
	 * Initialize the device.
	 *
	 * @throws DevFailed if something fails during the device initialization.
	 */
	@Init(lazyLoading = false)
	public void initDevice() throws DevFailed {
		xlogger.entry();
		logger.debug("init device " + deviceManager.getName());
		/*----- PROTECTED REGION ID(MegaCoffee3k.initDevice) ENABLED START -----*/

		//	Put your device initialization code here

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.initDevice
		xlogger.exit();
	}

	/**
	 * all resources may be closed here. Collections may be also cleared.
	 *
	 * @throws DevFailed if something fails during the device object deletion.
	 */
	@Delete
	public void deleteDevice() throws DevFailed {
		xlogger.entry();
		/*----- PROTECTED REGION ID(MegaCoffee3k.deleteDevice) ENABLED START -----*/

		//	Put your device clearing code here

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.deleteDevice
		xlogger.exit();
	}

	/**
	 * Method called before and after command and attribute calls.
	 * @param ctx the invocation context
	 * @throws DevFailed if something fails during this method execution.
	 */
	@AroundInvoke
	public void aroundInvoke(final InvocationContext ctx) throws DevFailed {
		xlogger.entry();
			/*----- PROTECTED REGION ID(MegaCoffee3k.aroundInvoke) ENABLED START -----*/

			//	Put aroundInvoke code here

			/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.aroundInvoke
		xlogger.exit();
	}


	/**
	 * dynamic command and attribute management. Will be injected by the framework.
	 */
	@DynamicManagement
	protected DynamicManager dynamicManager;
	/**
	 * @param dynamicManager the DynamicManager instance
	 * @throws DevFailed if something fails during this method execution.
	 */
	public void setDynamicManager(final DynamicManager dynamicManager) throws DevFailed {
		this.dynamicManager = dynamicManager;
		/*----- PROTECTED REGION ID(MegaCoffee3k.setDynamicManager) ENABLED START -----*/

		//	Put your code here

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.setDynamicManager
	}

	/**
	 * Device management. Will be injected by the framework.
	 */
	@DeviceManagement
	DeviceManager deviceManager;
	public void setDeviceManager(DeviceManager deviceManager){
		this.deviceManager= deviceManager ;
	}




	//========================================================
	//	Command data members and related methods
	//========================================================
	/**
	 * The state of the device
	*/
	@State
	private DevState state = DevState.UNKNOWN;
	/**
	 * Execute command "State".
	 * description: This command gets the device state (stored in its 'state' data member) and returns it to the caller.
	 * @return Device state
	 * @throws DevFailed if command execution failed.
	 */
	public final DevState getState() throws DevFailed {
		/*----- PROTECTED REGION ID(MegaCoffee3k.getState) ENABLED START -----*/

		//	Put state code here

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.getState
		return state;
	}
	/**
	 * Set the device state
	 * @param state the new device state
	 */
	public void setState(final DevState state) {
		this.state = state;
	}

	/**
	 * The status of the device
	 */
	@Status
	private String status = "Server is starting. The device state is unknown";
	/**
	 * Execute command "Status".
	 * description: This command gets the device status (stored in its 'status' data member) and returns it to the caller.
	 * @return Device status
	 * @throws DevFailed if command execution failed.
	 */
	public final String getStatus() throws DevFailed {
		/*----- PROTECTED REGION ID(MegaCoffee3k.getStatus) ENABLED START -----*/

		//	Put status code here

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.getStatus
		return status;
	}
	/**
	 * Set the device status
	 * @param status the new device status
	 */
	public void setStatus(final String status) {
		this.status = status;
	}


	//========================================================
	//	Programmer's methods
	//========================================================
	/*----- PROTECTED REGION ID(MegaCoffee3k.methods) ENABLED START -----*/

	//	Put your own methods here

	/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.methods






	/**
	 * Starts the server.
	 * @param args program arguments (instance_name [-v[trace level]]  [-nodb [-dlist <device name list>] [-file=fileName]])
	 */
	public static void main(final String[] args) {
		/*----- PROTECTED REGION ID(MegaCoffee3k.main) ENABLED START -----*/

		/*----- PROTECTED REGION END -----*/	//	MegaCoffee3k.main
		ServerManager.getInstance().start(args, MegaCoffee3k.class);
		System.out.println("------- Started -------------");
	}
}

Here the set_state and set_status methods have been used to modify the device’s state and status on startup.

If you run this example, and in a second terminal, use the device proxy client to check if it is working :

>>> dp.State()
tango._tango.DevState.OFF
>>> dp.Status()
'Hello world - device is off.'
>>>

It works, super easy!

Tip

It is good practice to set the state and status values at the same time, since clients will often read both of them, and they need to agree.

The DevState enum has many values, including STANDBY, ON, RUNNING, ALARM, and FAULT.

But what was that init_device method? It is part of the device implementation class, and it is called automatically when the device starts up. You’ll learn more about it soon.