#!/usr/bin/env python
"""Control panel system level (SL) temperature control
Author: <NAME>
Date created: 2009-10-14
Date last modified: 2019-05-21
"""
import wx,wx3_compatibility
from temperature import temperature
from oasis_chiller import oasis_chiller as oasis
from EditableControls import ComboBox,TextCtrl
from logging import debug
from Panel import BasePanel,PropertyPanel,TogglePanel,TweakPanel

__version__ = "4.6" # title

class Temperature_Panel (wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,parent=None,title="Temperature SL")

        # Icon
        from Icon import SetIcon
        SetIcon(self,"temperature")

        # Controls
        panel = wx.Panel(self)
        style = wx.TE_PROCESS_ENTER
        self.SetPoint = ComboBox(panel,style=style)

        style = wx.TE_READONLY
        self.ActualTemperature = wx.TextCtrl(panel,style=style)
        self.OasisActualTemperature = wx.TextCtrl(panel,style=style)
        self.CurrentPower = wx.TextCtrl(panel,style=style)

        self.LiveCheckBox = wx.CheckBox (panel,label="Live")
        self.RefreshButton = wx.Button (panel,label="Refresh",size=(65,-1))
        self.MoreButton = wx.Button (panel,label="More...",size=(60,-1))
        self.SettingsButton = wx.Button (panel,label="Settings...",size=(60,-1))
        w,h = self.MoreButton.Size
        self.AboutButton = wx.Button (panel,label="?",size=(h*1.25,h*0.75))

        # Callbacks
        self.Bind (wx.EVT_TEXT_ENTER,self.OnEnterSetPoint,self.SetPoint)
        self.Bind (wx.EVT_COMBOBOX,self.OnEnterSetPoint,self.SetPoint)

        self.Bind (wx.EVT_CHECKBOX,self.OnLive,self.LiveCheckBox)
        self.Bind (wx.EVT_BUTTON,self.OnRefresh,self.RefreshButton)
        self.Bind (wx.EVT_BUTTON,self.OnMore,self.MoreButton)
        self.Bind (wx.EVT_BUTTON,self.OnAbout,self.AboutButton)
        self.Bind (wx.EVT_BUTTON,self.OnTemperature,self.SettingsButton)

        # Layout
        layout = wx.GridBagSizer(1,1)
        a = wx.ALIGN_CENTRE_VERTICAL
        e = wx.EXPAND

        # Under Linux, if the version of wxWidget is 2.6 or older,
        # the label size needs to be specified to prevent line wrapping.
        # (This bug has been corrected in version 2.8).
        layout.Add (wx.StaticText(panel,label="Set Point:"),(0,0),flag=a)
        layout.Add (self.SetPoint,(0,1),flag=a|e)

        t = wx.StaticText(panel,label="Actual Temperature:")
        layout.Add (t,(1,0),flag=a)
        layout.Add (self.ActualTemperature,(1,1),flag=a|e)

        t = wx.StaticText(panel,label="Oasis Temperature:")
        layout.Add (t,(1,2),flag=a)
        layout.Add (self.OasisActualTemperature,(1,3),flag=a|e)

        t = wx.StaticText(panel,label="Current / Power:")
        layout.Add (t,(2,0),flag=a)
        layout.Add (self.CurrentPower,(2,1),flag=a|e)

        buttons = wx.BoxSizer(wx.HORIZONTAL)
        buttons.Add (self.LiveCheckBox,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.RefreshButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.MoreButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.SettingsButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.AboutButton,flag=wx.ALIGN_CENTER_VERTICAL)

        # Leave a 5 pixel wide border.
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add (layout,flag=wx.ALL,border=5)
        box.Add (buttons,flag=wx.ALL|wx.ALIGN_CENTER_HORIZONTAL,border=5)
        panel.SetSizer(box)
        panel.Fit()
        self.Fit()

        self.Show()

        # Restore saved history.
        config_dir = wx.StandardPaths.Get().GetUserDataDir()
        config_file = config_dir+"/TemperatureController.py"
        self.config = wx.FileConfig (localFilename=config_file)
        value = self.config.Read('History')
        if value: self.history = eval(value)
        else: self.history = []
        self.update_history()
        # Initialization
        self.timer = wx.Timer(self)
        self.Bind (wx.EVT_TIMER,self.refresh,self.timer)
        self.timer.Start(1000,oneShot=True)

    def update_history(self):
        """Update the pull down menu for the set point."""
        self.SetPoint.Clear() # clears menu
        choices = []
        for T in sorted(set(self.history)): choices += [str(T)]
        self.SetPoint.AppendItems(choices)

    def OnEnterSetPoint(self,event):
        """Called when typing Enter in the position field.
        or selecting a choice from the combo box drop down menu"""
        text = self.SetPoint.Value
        try: T = float(eval(text.replace("C","")))
        except: self.refresh(); return
        temperature.command_value = T

        self.history = self.history[-20:]+[T]
        self.update_history()

        self.refresh()

        # Make sure the history gets saved.
        config_dir = wx.StandardPaths.Get().GetUserDataDir()
        from os.path import exists
        from os import makedirs
        if not exists(config_dir): makedirs(config_dir)
        self.config.Write ('history',repr(self.history))
        self.config.Flush()

    def OnLive(self,event):
        """Called when the 'Live' checkbox is either checked or unchecked."""
        self.RefreshButton.Enabled = not self.LiveCheckBox.Value
        if self.LiveCheckBox.Value == True: self.keep_alive()

    def keep_alive(self,event=None):
        """Periodically refresh te displayed settings (every second)."""
        if self.LiveCheckBox.Value == False: return
        self.refresh()
        self.timer = wx.Timer(self)
        self.Bind (wx.EVT_TIMER,self.keep_alive,self.timer)
        self.timer.Start(250,oneShot=True)

    def OnRefresh(self,event):
        """Called when refrsh button is pressed"""
        self.refresh()

    def refresh(self,event=None):
        """Update displayed values"""
        value = tofloat(temperature.command_value)
        self.SetPoint.Value = "%.3f C" % value if not isnan(value) else ""

        value = temperature.value
        self.ActualTemperature.Value = "%.3f C"%value if not isnan(value) else ""
        value = oasis.value
        self.OasisActualTemperature.Value = "%.3f C"%value if not isnan(value) else ""

        moving = temperature.moving
        self.ActualTemperature.ForegroundColour = (255,0,0) if moving else (0,0,0)

        moving = oasis.moving
        self.OasisActualTemperature.ForegroundColour = (255,0,0) if moving else (0,0,0)
        ##self.ActualTemperature.BackgroundColour = (255,235,235) if moving else (255,255,255)

        current = temperature.I
        current = "%.3f A" % current if not isnan(current) else ""
        power = temperature.P
        power = "%.3f W" % power if not isnan(power) else ""
        self.CurrentPower.Value = "%s / %s" % (current,power)

    def OnMore(self,event):
        """Display panel with additional parameters."""
        self.parameter_panel = ParameterPanel(self)

    def OnTemperature(self,event):
        """Show panel with temperature ramp parameters"""
        self.temperature_ramp_panel = Temperature(self)

    def OnAbout(self,event):
        "Called from the Help/About"
        from os.path import basename
        from inspect import getfile
        filename = getfile(lambda x: None)
        info = basename(filename)+" "+__version__+"\n"+__doc__
        dlg = wx.MessageDialog(self,info,"About",wx.OK|wx.ICON_INFORMATION)
        dlg.CenterOnParent()
        dlg.ShowModal()
        dlg.Destroy()


class ParameterPanel(BasePanel):
    name = "parameters"
    title = "Parameters"
    standard_view = [
        "EPICS Record",
    ]
    parameters = [
        [[PropertyPanel,"EPICS Record",temperature,"prefix"],{"choices":["NIH:TEMP","NIH:LIGHTWAVE"],"refresh_period":1.0}],
    ]

    def __init__(self,parent=None):
        BasePanel.__init__(self,
            parent=parent,
            name=self.name,
            title=self.title,
            parameters=self.parameters,
            standard_view=self.standard_view,
            subname=True,
            refresh=True,
            live=True,
            label_width=90,
        )

class Temperature(BasePanel):
    name = "temperature"
    title = "Temperature"
    standard_view = [
        "Temp Points",
        "Time Points",
        "P default",
        "I default",
        "D default",
        "Lightwave prefix",
        "Oasis slave (on/off)",
        "Oasis threshold T",
        "Oasis idle temperature (low limit) (C)",
        "Oasis temperature limit high (C)",
        "Oasis headstart time (s)",
        "Oasis prefix",
        "set point update period (s)",
    ]
    parameters = [
        [[PropertyPanel,"Temp Points",temperature,"temp_points" ],{}],
        [[PropertyPanel,"Time Points",temperature,"time_points" ],{}],

        [[PropertyPanel,"P default",temperature,"P_default" ],{}],
        [[PropertyPanel,"I default",temperature,"I_default" ],{}],
        [[PropertyPanel,"D default",temperature,"D_default" ],{}],
        [[PropertyPanel,"Lightwave prefix",temperature,"lightwave_prefix"],{}],
        [[PropertyPanel,"Oasis slave (on/off)",temperature,"oasis_slave" ],{}],
        [[PropertyPanel,"Oasis threshold T",temperature,"T_threshold" ],{}],
        [[PropertyPanel,"Oasis idle temperature (low limit) (C)",temperature,"idle_temperature_oasis" ],{}],
        [[PropertyPanel,"Oasis temperature limit high (C)",temperature,"temperature_oasis_limit_high" ],{}],
        [[PropertyPanel,"Oasis headstart time (s)",temperature,"oasis_headstart_time" ],{}],
        [[PropertyPanel,"Oasis prefix",temperature,"oasis_prefix" ],{}],
    ]

    def __init__(self,parent=None):
        BasePanel.__init__(self,
            parent=parent,
            name=self.name,
            title=self.title,
            parameters=self.parameters,
            standard_view=self.standard_view,
            subname=True,
            refresh=True,
            live=True,
            label_width=90,
        )

def isnan(x):
    """Is x 'not a number' or 'None'"""
    from numpy import isnan
    try: return isnan(float(x))
    except: return True

def tostr(x):
    """Convert x to string."""
    if x is None: return ""
    return str(x)

def tofloat(x):
    """Convert x to float if possible, else return nan"""
    from numpy import nan
    try: x = float(x)
    except: x = nan
    return x

def toint(x):
    """Convert x to int if possible, else return nan"""
    from numpy import nan
    try: x = int(x)
    except: x = nan
    return x

if __name__ == '__main__':
    from pdb import pm
    import logging; from tempfile import gettempdir
    logfile = gettempdir()+"/Temperature_Panel.log"
    logging.basicConfig(level=logging.DEBUG,format="%(asctime)s: %(message)s",
       filename=logfile)
    logging.debug("Temperature Panel started")
    # Needed to initialize WX library
    if not "app" in globals(): app = wx.App(redirect=False)
    panel = Temperature_Panel()
    app.MainLoop()

#!/usr/bin/env python
"""Control panel system level (SL) temperature control
Author: <NAME>
Date created: 2009-10-14
Date last modified: 2019-05-21
"""
import wx,wx3_compatibility
from temperature import temperature
from oasis_chiller import oasis_chiller as oasis
from EditableControls import ComboBox,TextCtrl
from logging import debug
from Panel import BasePanel,PropertyPanel,TogglePanel,TweakPanel

__version__ = "4.6" # title

class Temperature_Panel (wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,parent=None,title="Temperature SL")

        # Icon
        from Icon import SetIcon
        SetIcon(self,"temperature")

        # Controls
        panel = wx.Panel(self)
        style = wx.TE_PROCESS_ENTER
        self.SetPoint = ComboBox(panel,style=style)

        style = wx.TE_READONLY
        self.ActualTemperature = wx.TextCtrl(panel,style=style)
        self.OasisActualTemperature = wx.TextCtrl(panel,style=style)
        self.CurrentPower = wx.TextCtrl(panel,style=style)

        self.LiveCheckBox = wx.CheckBox (panel,label="Live")
        self.RefreshButton = wx.Button (panel,label="Refresh",size=(65,-1))
        self.MoreButton = wx.Button (panel,label="More...",size=(60,-1))
        self.SettingsButton = wx.Button (panel,label="Settings...",size=(60,-1))
        w,h = self.MoreButton.Size
        self.AboutButton = wx.Button (panel,label="?",size=(h*1.25,h*0.75))

        # Callbacks
        self.Bind (wx.EVT_TEXT_ENTER,self.OnEnterSetPoint,self.SetPoint)
        self.Bind (wx.EVT_COMBOBOX,self.OnEnterSetPoint,self.SetPoint)

        self.Bind (wx.EVT_CHECKBOX,self.OnLive,self.LiveCheckBox)
        self.Bind (wx.EVT_BUTTON,self.OnRefresh,self.RefreshButton)
        self.Bind (wx.EVT_BUTTON,self.OnMore,self.MoreButton)
        self.Bind (wx.EVT_BUTTON,self.OnAbout,self.AboutButton)
        self.Bind (wx.EVT_BUTTON,self.OnTemperature,self.SettingsButton)

        # Layout
        layout = wx.GridBagSizer(1,1)
        a = wx.ALIGN_CENTRE_VERTICAL
        e = wx.EXPAND

        # Under Linux, if the version of wxWidget is 2.6 or older,
        # the label size needs to be specified to prevent line wrapping.
        # (This bug has been corrected in version 2.8).
        layout.Add (wx.StaticText(panel,label="Set Point:"),(0,0),flag=a)
        layout.Add (self.SetPoint,(0,1),flag=a|e)

        t = wx.StaticText(panel,label="Actual Temperature:")
        layout.Add (t,(1,0),flag=a)
        layout.Add (self.ActualTemperature,(1,1),flag=a|e)

        t = wx.StaticText(panel,label="Oasis Temperature:")
        layout.Add (t,(1,2),flag=a)
        layout.Add (self.OasisActualTemperature,(1,3),flag=a|e)

        t = wx.StaticText(panel,label="Current / Power:")
        layout.Add (t,(2,0),flag=a)
        layout.Add (self.CurrentPower,(2,1),flag=a|e)

        buttons = wx.BoxSizer(wx.HORIZONTAL)
        buttons.Add (self.LiveCheckBox,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.RefreshButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.MoreButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.SettingsButton,flag=wx.ALIGN_CENTER_VERTICAL)
        buttons.AddSpacer(5)
        buttons.Add (self.AboutButton,flag=wx.ALIGN_CENTER_VERTICAL)

        # Leave a 5 pixel wide border.
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add (layout,flag=wx.ALL,border=5)
        box.Add (buttons,flag=wx.ALL|wx.ALIGN_CENTER_HORIZONTAL,border=5)
        panel.SetSizer(box)
        panel.Fit()
        self.Fit()

        self.Show()

        # Restore saved history.
        config_dir = wx.StandardPaths.Get().GetUserDataDir()
        config_file = config_dir+"/TemperatureController.py"
        self.config = wx.FileConfig (localFilename=config_file)
        value = self.config.Read('History')
        if value: self.history = eval(value)
        else: self.history = []
        self.update_history()
        # Initialization
        self.timer = wx.Timer(self)
        self.Bind (wx.EVT_TIMER,self.refresh,self.timer)
        self.timer.Start(1000,oneShot=True)

    def update_history(self):
        """Update the pull down menu for the set point."""
        self.SetPoint.Clear() # clears menu
        choices = []
        for T in sorted(set(self.history)): choices += [str(T)]
        self.SetPoint.AppendItems(choices)

    def OnEnterSetPoint(self,event):
        """Called when typing Enter in the position field.
        or selecting a choice from the combo box drop down menu"""
        text = self.SetPoint.Value
        try: T = float(eval(text.replace("C","")))
        except: self.refresh(); return
        temperature.command_value = T

        self.history = self.history[-20:]+[T]
        self.update_history()

        self.refresh()

        # Make sure the history gets saved.
        config_dir = wx.StandardPaths.Get().GetUserDataDir()
        from os.path import exists
        from os import makedirs
        if not exists(config_dir): makedirs(config_dir)
        self.config.Write ('history',repr(self.history))
        self.config.Flush()

    def OnLive(self,event):
        """Called when the 'Live' checkbox is either checked or unchecked."""
        self.RefreshButton.Enabled = not self.LiveCheckBox.Value
        if self.LiveCheckBox.Value == True: self.keep_alive()

    def keep_alive(self,event=None):
        """Periodically refresh te displayed settings (every second)."""
        if self.LiveCheckBox.Value == False: return
        self.refresh()
        self.timer = wx.Timer(self)
        self.Bind (wx.EVT_TIMER,self.keep_alive,self.timer)
        self.timer.Start(250,oneShot=True)

    def OnRefresh(self,event):
        """Called when refrsh button is pressed"""
        self.refresh()

    def refresh(self,event=None):
        """Update displayed values"""
        value = tofloat(temperature.command_value)
        self.SetPoint.Value = "%.3f C" % value if not isnan(value) else ""

        value = temperature.value
        self.ActualTemperature.Value = "%.3f C"%value if not isnan(value) else ""
        value = oasis.value
        self.OasisActualTemperature.Value = "%.3f C"%value if not isnan(value) else ""

        moving = temperature.moving
        self.ActualTemperature.ForegroundColour = (255,0,0) if moving else (0,0,0)

        moving = oasis.moving
        self.OasisActualTemperature.ForegroundColour = (255,0,0) if moving else (0,0,0)
        ##self.ActualTemperature.BackgroundColour = (255,235,235) if moving else (255,255,255)

        current = temperature.I
        current = "%.3f A" % current if not isnan(current) else ""
        power = temperature.P
        power = "%.3f W" % power if not isnan(power) else ""
        self.CurrentPower.Value = "%s / %s" % (current,power)

    def OnMore(self,event):
        """Display panel with additional parameters."""
        self.parameter_panel = ParameterPanel(self)

    def OnTemperature(self,event):
        """Show panel with temperature ramp parameters"""
        self.temperature_ramp_panel = Temperature(self)

    def OnAbout(self,event):
        "Called from the Help/About"
        from os.path import basename
        from inspect import getfile
        filename = getfile(lambda x: None)
        info = basename(filename)+" "+__version__+"\n"+__doc__
        dlg = wx.MessageDialog(self,info,"About",wx.OK|wx.ICON_INFORMATION)
        dlg.CenterOnParent()
        dlg.ShowModal()
        dlg.Destroy()


class ParameterPanel(BasePanel):
    name = "parameters"
    title = "Parameters"
    standard_view = [
        "EPICS Record",
    ]
    parameters = [
        [[PropertyPanel,"EPICS Record",temperature,"prefix"],{"choices":["NIH:TEMP","NIH:LIGHTWAVE"],"refresh_period":1.0}],
    ]

    def __init__(self,parent=None):
        BasePanel.__init__(self,
            parent=parent,
            name=self.name,
            title=self.title,
            parameters=self.parameters,
            standard_view=self.standard_view,
            subname=True,
            refresh=True,
            live=True,
            label_width=90,
        )

class Temperature(BasePanel):
    name = "temperature"
    title = "Temperature"
    standard_view = [
        "Temp Points",
        "Time Points",
        "P default",
        "I default",
        "D default",
        "Lightwave prefix",
        "Oasis slave (on/off)",
        "Oasis threshold T",
        "Oasis idle temperature (low limit) (C)",
        "Oasis temperature limit high (C)",
        "Oasis headstart time (s)",
        "Oasis prefix",
        "set point update period (s)",
    ]
    parameters = [
        [[PropertyPanel,"Temp Points",temperature,"temp_points" ],{}],
        [[PropertyPanel,"Time Points",temperature,"time_points" ],{}],

        [[PropertyPanel,"P default",temperature,"P_default" ],{}],
        [[PropertyPanel,"I default",temperature,"I_default" ],{}],
        [[PropertyPanel,"D default",temperature,"D_default" ],{}],
        [[PropertyPanel,"Lightwave prefix",temperature,"lightwave_prefix"],{}],
        [[PropertyPanel,"Oasis slave (on/off)",temperature,"oasis_slave" ],{}],
        [[PropertyPanel,"Oasis threshold T",temperature,"T_threshold" ],{}],
        [[PropertyPanel,"Oasis idle temperature (low limit) (C)",temperature,"idle_temperature_oasis" ],{}],
        [[PropertyPanel,"Oasis temperature limit high (C)",temperature,"temperature_oasis_limit_high" ],{}],
        [[PropertyPanel,"Oasis headstart time (s)",temperature,"oasis_headstart_time" ],{}],
        [[PropertyPanel,"Oasis prefix",temperature,"oasis_prefix" ],{}],
    ]

    def __init__(self,parent=None):
        BasePanel.__init__(self,
            parent=parent,
            name=self.name,
            title=self.title,
            parameters=self.parameters,
            standard_view=self.standard_view,
            subname=True,
            refresh=True,
            live=True,
            label_width=90,
        )

def isnan(x):
    """Is x 'not a number' or 'None'"""
    from numpy import isnan
    try: return isnan(float(x))
    except: return True

def tostr(x):
    """Convert x to string."""
    if x is None: return ""
    return str(x)

def tofloat(x):
    """Convert x to float if possible, else return nan"""
    from numpy import nan
    try: x = float(x)
    except: x = nan
    return x

def toint(x):
    """Convert x to int if possible, else return nan"""
    from numpy import nan
    try: x = int(x)
    except: x = nan
    return x

if __name__ == '__main__':
    from pdb import pm
    import logging; from tempfile import gettempdir
    logfile = gettempdir()+"/Temperature_Panel.log"
    logging.basicConfig(level=logging.DEBUG,format="%(asctime)s: %(message)s",
       filename=logfile)
    logging.debug("Temperature Panel started")
    # Needed to initialize WX library
    if not "app" in globals(): app = wx.App(redirect=False)
    panel = Temperature_Panel()
    app.MainLoop()

#!/usr/bin/env python Control panel system level (SL) temperature control Author: <NAME> Date created: 2009-10-14 Date last modified: 2019-05-21 # title # Icon # Controls # Callbacks # Layout # Under Linux, if the version of wxWidget is 2.6 or older, # the label size needs to be specified to prevent line wrapping. # (This bug has been corrected in version 2.8). # Leave a 5 pixel wide border. # Restore saved history. # Initialization Update the pull down menu for the set point. # clears menu Called when typing Enter in the position field.         or selecting a choice from the combo box drop down menu # Make sure the history gets saved. Called when the 'Live' checkbox is either checked or unchecked. Periodically refresh te displayed settings (every second). Called when refrsh button is pressed Update displayed values ##self.ActualTemperature.BackgroundColour = (255,235,235) if moving else (255,255,255) Display panel with additional parameters. Show panel with temperature ramp parameters Is x 'not a number' or 'None' Convert x to string. Convert x to float if possible, else return nan Convert x to int if possible, else return nan # Needed to initialize WX library