Commit a88f742a authored by Gallacchi Mattia's avatar Gallacchi Mattia
Browse files

Merge branch '1-add-ci-cd' into 'main'

Add ci file

Closes #1

See merge request !1
parents 439d8696 8d4fc684
Loading
Loading
Loading
Loading
Loading

.gitlab-ci.yml

0 → 100644
+67 −0
Original line number Diff line number Diff line
# This file is a template, and might need editing before it works on your project.
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
# it uses echo commands to simulate the pipeline execution.
#
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
# Stages run in sequential order, but jobs within stages run in parallel.
#
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
#
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml

stages:          # List of stages for jobs, and their order of execution
  - lint
  - deploy

default:
  image:
    name: labinfo.ing.he-arc.ch:5050/igib/shared/ci-docker/poetry1.2.0-python3.10
    entrypoint: [ "" ]

lint-black:
  stage: lint
  tags:
    - docker
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
      allow_failure: false
  script:
    - poetry install --only lint
    - poetry run black --check ms210/

lint-pylint:
  stage: lint
  tags:
    - docker
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
      allow_failure: false
  script:
    - poetry install --only lint
    - poetry run pylint --fail-under=8 ms210/

deploy-job:      # This job runs only when the merge is accepted
  stage: deploy  # It only runs when *both* jobs in the test stage complete successfully.
  tags:
    - docker
  environment: production
  rules:
    - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"
      when: always
    - when: never

  script:
    - poetry install --only main
    - poetry config repositories.gitlab https://labinfo.ing.he-arc.ch/gitlab/api/v4/projects/$CI_PROJECT_ID/packages/pypi
    - poetry config http-basic.gitlab gitlab-ci-token "$CI_JOB_TOKEN"
    - poetry build
    - poetry publish --repository gitlab
 No newline at end of file
+57 −5
Original line number Diff line number Diff line
@@ -2,6 +2,14 @@

This repository contains a small python module to control the MS210 Channel Mixer by Advanced Illumination

> **NOTE**:
> 
> For linux user add your user to the *dialout* group to access the serial port
>
> ```bash
> sudo usermod -aG dialout $USER
> ```

## Dependencies

| Name | Version |
@@ -9,13 +17,57 @@ This repository contains a small python module to control the MS210 Channel Mixe
| Python | >= 3.10 |
| Poetry | >= 1.2.0 |

## Add package
Install python dependencies:

```bash
poetry install
```

TODO: 
## App

## Linux
For linux user add your user to the *dialout* group to access the serial port
A QT based graphical interface to control the **MS210** is available and can be run with the following command:

```bash
sudo usermod -aG dialout $USER
poetry run controller
```

![UI](img/ms210_ui.png)

## Add the MS210 package

Instructions to add the MS210 package to your project

### Poetry

Add a secondary source to your poetry project

```bash
poetry source add -s igib https://labinfo.ing.he-arc.ch/gitlab/api/v4/projects/2417/packages/pypi/simple
```

Add **ms210** package

```bash
poetry add ms210 --source igib
```

### PIP

```bash
pip install pyrsvp --index-url https://labinfo.ing.he-arc.ch/gitlab/api/v4/projects/2417/packages/pypi/simple/
```

## Usage

```python
dev = MS210("/dev/ttyUSB0")

# Set the red value
success, msg = dev.set_value("R", 500)
if not success:
    print(msg)

# Get the green value
green = dev.get_value("G")
print(green)
```
 No newline at end of file
+12 −4
Original line number Diff line number Diff line
import sys
from typing import Literal
from PyQt6.QtGui import QCloseEvent

from PyQt6.QtWidgets import QApplication, QMainWindow, QMessageBox
from ms210_ui import Ui_MainWindow
from app.ms210_ui import Ui_MainWindow

from ms210.driver import MS210, MS210InitFailed
import serial.tools.list_ports
@@ -141,9 +142,16 @@ class Window(QMainWindow, Ui_MainWindow):
    def error_msg(self, msg : str):
        QMessageBox.critical(None, "Error", msg)

if "__main__" == __name__:
    def closeEvent(self, a0: QCloseEvent) -> None:
        self._ms210 = None
        return super().closeEvent(a0)      

def main():

    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

if "__main__" == __name__:
    main()
 No newline at end of file

img/ms210_ui.png

0 → 100644
+10.2 KiB
Loading image diff...
+31 −20
Original line number Diff line number Diff line
# This module contains a class to control the MS210 device
"""This module contains a class to control the MS210 device
"""

import serial
from typing import Literal
from dataclasses import dataclass
import serial

_BAUD = 19200
_CHANNELS = ["IR", "R", "B", "G"]
_MAX_VALUE = 1000
_MIN_VALUE = 0


@dataclass
class Channel:
    """Holds channel attributes"""

    name: str
    index: int
    value: int


class MS210InitFailed(Exception):
    pass
    """MS210 serial communication failed"""


class MS210:
    """MS210 driver class"""

    def __init__(self, port: str = "/dev/ttyUSB0"):
        """Constructor of the MS210 object
@@ -52,8 +59,7 @@ class MS210:
            raise MS210InitFailed(msg)

    def __del__(self):
        """Destructor
        """
        """Destructor"""
        for channel in _CHANNELS:
            self.set_value(channel, 0)

@@ -124,7 +130,9 @@ class MS210:

        return [x for x in self.channels if x.name == channel][0].value

    def set_value(self, channel: Literal["IR", "R", "B", "G"], value : int = 0) -> tuple[bool, str]:
    def set_value(
        self, channel: Literal["IR", "R", "B", "G"], value: int = 0
    ) -> tuple[bool, str]:
        """Set the value of a channel

        Parameters
@@ -141,7 +149,10 @@ class MS210:
        """

        if not self.__check_limits(value):
            return (False, f"Value {value} is out of bound. {_MIN_VALUE} < value < {_MAX_VALUE}")
            return (
                False,
                f"Value {value} is out of bound. {_MIN_VALUE} < value < {_MAX_VALUE}",
            )

        _channel = [x for x in self.channels if x.name == channel][0]
        if value == _channel.value:
Loading