PyTango Device Servers are not managed with Starter/Astor under Windows

Hello,

I want to manage PyTango Device Servers (DS) with Starter DS under Windows 10.

The subject had already been discussed on the forum (for example here — https://www.tango-controls.org/community/forum/c/development/python/python-and-astor/ ). However, I still did not find a clear answer. Also, the subject is not covered in the official guide.

——————–

All Tango stuff are running under Windows 10 x64:

1. TangoSetup-9.2.2_win64.exe including:
1.1 TangoTest.exe
1.2 Starter.exe (StartDsPath = C:\Tango\DeviceServers)
2. Python 3.8.8 (conda)
2.1 PyTango 9.3.3 (pip)

C:\Tango\DeviceServers\TangoTest.exe are fully managed with Starter (start/restart/etc).

But PyTango Device Servers are not. What does it mean:

1. When I started PyTango DS manually (python DS.py) I can see "green" state in Astor or server name are listed in the response to the direct query to Starter DS (DevGetRunningServers command)
2. I can to kill running PyTango DS with Astor/direct query to Starter.
3. But I can't start PyTango DS with Astor/direct query to Starter ("red" state). And I can't restart it too (killed ok, but can't started after)
My test PyTango Device Servers for Windows environment (see code below):

1. C:\Tango\DeviceServers\PowerSupply.py
2. C:\Tango\DeviceServers\PowerSupply.bat (script launcher for Windows env).

Starter logs at C:\Temp doesn't provide any useful info.

Is there any ideas? What else would you recommend to check?

——————–

Test PyTango Device Server

C:\Tango\DeviceServers\PowerSupply.py


# example from https://pytango.readthedocs.io/en/latest/quicktour.html#server

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Demo power supply tango device server"""

import time
import numpy

from tango import AttrQuality, AttrWriteType, DispLevel, DevState, DebugIt
from tango.server import Device, attribute, command, pipe, device_property
class PowerSupply(Device):

voltage = attribute(label="Voltage", dtype=float,
display_level=DispLevel.OPERATOR,
access=AttrWriteType.READ,
unit="V", format="8.4f",
doc="the power supply voltage")

current = attribute(label="Current", dtype=float,
display_level=DispLevel.EXPERT,
access=AttrWriteType.READ_WRITE,
unit="A", format="8.4f",
min_value=0.0, max_value=8.5,
min_alarm=0.1, max_alarm=8.4,
min_warning=0.5, max_warning=8.0,
fget="get_current",
fset="set_current",
doc="the power supply current")

noise = attribute(label="Noise",
dtype=((int,),),
max_dim_x=1024, max_dim_y=1024)

info = pipe(label='Info')

host = device_property(dtype=str)
port = device_property(dtype=int, default_value=9788)

def init_device(self):
Device.init_device(self)
self.__current = 0.0
self.set_state(DevState.STANDBY)

def read_voltage(self):
self.info_stream("read_voltage(%s, %d)", self.host, self.port)
return 9.99, time.time(), AttrQuality.ATTR_WARNING

def get_current(self):
return self.__current

def set_current(self, current):
# should set the power supply current
self.__current = current

def read_info(self):
return 'Information', dict(manufacturer='Tango',
model='PS2000',
version_number=123)

@DebugIt()
def read_noise(self):
return numpy.random.random_integers(1000, size=(100, 100))

@command
def TurnOn(self):
# turn on the actual power supply here
self.set_state(DevState.ON)

@command
def TurnOff(self):
# turn off the actual power supply here
self.set_state(DevState.OFF)

@command(dtype_in=float, doc_in="Ramp target current",
dtype_out=bool, doc_out="True if ramping went well, "
"False otherwise")
def Ramp(self, target_current):
# should do the ramping
return True
def register():
"""
python -c "from PowerSupply import register; register()"
"""
import tango

dev_info = tango.DbDevInfo()
dev_info.server = "PowerSupply/test"
dev_info._class = "PowerSupply"
dev_info.name = "test/power_supply/1"

db = tango.Database()
db.add_device(dev_info)
if __name__ == "__main__":
from tango.server import run
run((PowerSupply, ))



C:\Tango\DeviceServers\PowerSupply.bat (Launcher)


@echo off
python.exe C:\Tango\DeviceServers\PowerSupply.py %1
We are successfully using PyTango and Astor on Windows 10 + Anaconda Python, so I'm confident you can solve your issue.
It must be related to the different PATH settings of your user and the SYSTEM account under which the nssm service is run (or other user if you chose so).

For it to simply work, it is important that `python` can be found on the PATH also when running inside the starter service. Here is an example batch file just like yours (%* appends all arguments, not just the first when e.g. adding -v4 debug option):

@echo off
python C:\tango-root\starter_bin\MicroscopeArduino.py %*


It should work like that if you install Anaconda/Python for the entire system:
  • During installation, I chose "add Anaconda to system PATH" even though it lights up as dangerous. I think it is only dangerous if you plan to use more than 1 version of python on that PC, but this is not the case for our lab computers.
  • Make sure `python` is on `PATH`, i.e. works from a normal windows console, not from "Anaconda Prompt". (in your case, this seems to be fine)
  • When running `python`, there may be a message that the environment is not activated. In some cases this worked fine for me, in others that failed to import packages like `numpy` etc.
  • Also check these things while running as a service, since services in Windows are executed as SYSTEM user which is different from e.g. Administrator (see below).

If you plan to use multiple environment or otherwise have reasons not to have anaconda on system PATH, this here works on a different lab computer where I think anaconda is not on PATH:

@echo off
call %CONDA_BASE%\Scripts\activate.bat
call conda activate base
python C:\tango-root\starter_bin\LaserControlServer.py %*


To check what might be going wrong, I suggest to replace the contents of your `PowerSupply.bat` with:

@echo off
where python > C:\temp\wherepy.log
set > C:\temp\envvars.log
python.exe C:\Tango\DeviceServers\PowerSupply.py %1 > C:\temp\pyout.log 2>&1


Then you can see if python can be found, if CONDA_ env vars are defined correctly, and finally if anything is going wrong during the starting of your python script (like packages not being loaded because of missing "conda activate" or permissions etc.).
The `2>&1` redirects both stdout and stderr to the file. The reason for absolute paths is because I believe Starter will set the working directory as `C:\temp\ds.log\` or so and to avoid needing to search around we set an absolute path.
 
Register or login to create to post a reply.