Source code for pzp_hardware.lightcon.pharos

# This file is a part of pzp-hardware, a library of laboratory hardware support Pieces
# for the puzzlepiece GUI & automation framework. Check out https://pzp-hardware.readthedocs.io
# Licensed under the Apache License 2.0 - https://github.com/jdranczewski/pzp-hardware/blob/main/LICENSE

r"""
:module_title:`Pharos laser control`

Pieces for interacting with
`Pharos lasers <https://lightcon.com/products/pharos-femtosecond-lasers/>`__
using the `puzzlepiece <https://puzzlepiece.readthedocs.io>`__ framework.

Example usage (see :ref:`getting-started` for more details on using Pieces in general)::

    import puzzlepiece as pzp
    from pzp_hardware.lightcon import pharos

    app = pzp.QApp()
    puzzle = pzp.Puzzle(debug=False)
    puzzle.add_piece("pharos", pharos.Piece, row=0, column=0, param_defaults={
        "address": "http://123.456.789.1:20022" # optionally specify a default IP address
    })
    puzzle.show()
    app.exec()

Installation
------------
* Find the IP address and port corresponding to the Pharos API.

  - On older Pharos systems, this will be local (so "http://127.0.0.1:20022" for example) if the
    control app is running on the same computer as the Piece. If the Pharos control app is running
    on a different computer, it will be that computer's IP and the same port. You have to select
    "Run REST server at startup" in the Pharos control app, and restart it. You can then select "help",
    which will open a help page in your browser - you can then see the port to use in the address bar.
    You may need to open this port in the Windows firewall to access it from another computer. It's best
    practice to restrict this access to specific computers, so you don't give control of your laser to
    everyone on the network.
  - On newer Pharos systems, this will be the IP address of the laser controller, so the IP you use
    to access the web-based control panel. You can select "REST API" from the top menu, and note the IP
    address and port in your browser's address bar.

* Install the ``requests`` library with pip, or wait to be prompted for automatic installation when first
  running the Piece.
* Paste the IP address and port you found in the "address" text box, or see above for setting it as the default
  in ``add_piece``.

Requirements
------------
.. pzp_requirements:: pzp_hardware.generic.hw_bases.http

Available Pieces
----------------
"""

import puzzlepiece as pzp
from puzzlepiece.extras import hardware_tools as pht
from pyqtgraph.Qt import QtWidgets

from pzp_hardware.generic.hw_bases import http


[docs] class Piece(http.Base): """ Pharos laser control Piece. .. image:: ../images/pzp_hardware.lightcon.pharos.Piece.png """ _api = "/v1" default_address = "http://127.0.0.1:20022" def define_params(self): super().define_params() address = self["address"] @pzp.param.readout(self, "full_state", visible=False) def basic(): if self.puzzle.debug: return "" r = self.rq.get(f"{address.value}{self._api}/Basic") self.check_response(r) state = str(r.json()).replace(",", ",\n") return state @pzp.param.readout(self, "state", visible=True) def basic(): if self.puzzle.debug: return "" r = self.rq.get(f"{address.value}{self._api}/Basic") self.check_response(r) return r.json()["GeneralStatus"] @pzp.param.checkbox(self, "output", 0) def output(value): if self.puzzle.debug: return value if value: r = self.rq.post(f"{address.value}{self._api}/Basic/EnableOutput") else: r = self.rq.post(f"{address.value}{self._api}/Basic/CloseOutput") self.check_response(r) return value @output.set_getter(self) def output(): if self.puzzle.debug: return output.value or 0 r = self.rq.get(f"{address.value}{self._api}/Basic/IsOutputEnabled") self.check_response(r) return r.text == "true" @pzp.param.spinbox(self, "divider", 1, v_min=1) def divider(value): if self.puzzle.debug: return value r = self.rq.put(f"{address.value}{self._api}/Basic/TargetPpDivider", str(value)) self.check_response(r) return value @divider.set_getter(self) def divider(): if self.puzzle.debug: return 1 r = self.rq.get(f"{address.value}{self._api}/Basic/TargetPpDivider") self.check_response(r) return int(r.text) def define_actions(self): super().define_actions() address = self["address"] @pzp.action.define(self, "Full state") def state(): state = self.params["full_state"].get_value() box = QtWidgets.QMessageBox() box.setText(state) box.exec() @pzp.action.define(self, "Standby") def shutdown(confirm=True): if confirm: mb = QtWidgets.QMessageBox if ( mb.question( self.puzzle, "Shutdown", "Do you want to go to standby?" ) != mb.StandardButton.Yes ): return if self.puzzle.debug: return r = self.rq.post(f"{address.value}{self._api}/Basic/GoToStandby") self.check_response(r) @pzp.action.define(self, "Shutdown") def shutdown(confirm=True): if confirm: mb = QtWidgets.QMessageBox if ( mb.question( self.puzzle, "Shutdown", "Do you want to turn off the laser?" ) != mb.StandardButton.Yes ): return if self.puzzle.debug: return r = self.rq.post(f"{address.value}{self._api}/Basic/TurnOff") self.check_response(r)
if __name__ == "__main__": app = pzp.QApp() puzzle = pzp.Puzzle(name="Pharos", debug=pht.debug_prompt()) puzzle.add_piece("pharos", Piece, 0, 0) puzzle.show() app.exec()