internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: microsoft/Qcodes

Issue:
DeprecationWarning when initializing SR830/SR86x lockins
### Steps to reproduce
1. Initialize an SR830 lockin

### Actual behaviour
Warning caused by calls to `set_validator` which has been deprecated in favor of directly setting `self.vals`

### System
Present as of 85b3958d177f4770224be0739c97f5b5ff202cef



Discussion:

Resolving patch:
diff --git a/qcodes/instrument_drivers/stanford_research/SR830.py b/qcodes/instrument_drivers/stanford_research/SR830.py
--- a/qcodes/instrument_drivers/stanford_research/SR830.py
+++ b/qcodes/instrument_drivers/stanford_research/SR830.py
@@ -550,20 +550,20 @@ def _get_input_config(self, s):
         mode = self._N_TO_INPUT_CONFIG[int(s)]
 
         if mode in ['a', 'a-b']:
-            self.sensitivity.set_validator(self._VOLT_ENUM)
+            self.sensitivity.vals = self._VOLT_ENUM
             self._set_units('V')
         else:
-            self.sensitivity.set_validator(self._CURR_ENUM)
+            self.sensitivity.vals = self._CURR_ENUM
             self._set_units('A')
 
         return mode
 
     def _set_input_config(self, s):
         if s in ['a', 'a-b']:
-            self.sensitivity.set_validator(self._VOLT_ENUM)
+            self.sensitivity.vals = self._VOLT_ENUM
             self._set_units('V')
         else:
-            self.sensitivity.set_validator(self._CURR_ENUM)
+            self.sensitivity.vals = self._CURR_ENUM
             self._set_units('A')
 
         return self._INPUT_CONFIG_TO_N[s]
diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py
--- a/qcodes/instrument_drivers/stanford_research/SR86x.py
+++ b/qcodes/instrument_drivers/stanford_research/SR86x.py
@@ -539,20 +539,20 @@ def _get_input_config(self, s):
         mode = self._N_TO_INPUT_SIGNAL[int(s)]
 
         if mode == 'voltage':
-            self.sensitivity.set_validator(self._VOLT_ENUM)
+            self.sensitivity.vals = self._VOLT_ENUM
             self._set_units('V')
         else:
-            self.sensitivity.set_validator(self._CURR_ENUM)
+            self.sensitivity.vals = self._CURR_ENUM
             self._set_units('A')
 
         return mode
 
     def _set_input_config(self, s):
         if s == 'voltage':
-            self.sensitivity.set_validator(self._VOLT_ENUM)
+            self.sensitivity.vals = self._VOLT_ENUM
             self._set_units('V')
         else:
-            self.sensitivity.set_validator(self._CURR_ENUM)
+            self.sensitivity.vals = self._CURR_ENUM
             self._set_units('A')
 
         return self._INPUT_SIGNAL_TO_N[s]


Test patch:
Repository: microsoft/Qcodes

Issue:
Exception setting range in QtPlot when using datasets containing NaN
### Steps to reproduce
1. Create a new DataSet containing a NaN value (i.e. start a new sweep and abort it)
2. Create a new QtPlot instance and try to plot the data

### Actual behaviour
I get the following traceback:
```pytb
>>> plot.add(data.Fifty_K)
Traceback (most recent call last):

  File "<ipython-input-59-c376a959841f>", line 1, in <module>
    plot.add(data.Fifty_K)

  File "c:\users\spauka\documents\qcodes\qcodes\plots\base.py", line 94, in add
    plot_object = self.add_to_plot(**kwargs)

  File "c:\users\spauka\documents\qcodes\qcodes\plots\pyqtgraph.py", line 177, in add_to_plot
    self.fixUnitScaling()

  File "c:\users\spauka\documents\qcodes\qcodes\plots\pyqtgraph.py", line 606, in fixUnitScaling
    rangesetter(arrmin, arrmax)

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 918, in __call__
    return self._handler.callObj(obj=self, args=args, kwds=kwds, **opts)

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 567, in callObj
    return self.send(request='callObj', opts=dict(obj=obj, args=args, kwds=kwds), byteData=byteMsgs, **opts)

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 470, in send
    return req.result()

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 636, in result
    while not self.hasResult():

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 654, in hasResult
    self.result(block=False)

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 647, in result
    self._result = self.proc.getResult(self.reqId)  ## raises NoResultError if result is not available yet

  File "C:\Users\spauka\Anaconda3\lib\site-packages\pyqtgraph\multiprocess\remoteproxy.py", line 508, in getResult
    raise exc

Exception: Cannot set range [nan, nan]
```

### System
Error exists as at 1ced7f362f06f2112b13b1122b90ba9c717c2cac



Discussion:

Resolving patch:
diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -581,8 +581,8 @@ def fixUnitScaling(self, startranges: Optional[Dict[str, Dict[str, Union[float,i
                     arrmin = None
                     arrmax = None
                     if setarr is not None and not np.all(np.isnan(setarr)):
-                        arrmax = setarr.max()
-                        arrmin = setarr.min()
+                        arrmax = np.nanmax(setarr)
+                        arrmin = np.nanmin(setarr)
                     elif startranges is not None:
                         try:
                             paramname = self.traces[i]['config'][axis].full_name


Test patch:
Repository: microsoft/Qcodes

Issue:
Binary blob inserted with some numpy types 
When we run the following code: 

```python
import numpy as np

import qcodes as qc
from qcodes import ParamSpec, new_data_set, new_experiment

dataSet = new_data_set("numpy_test")
parameter_a = ParamSpec("a", "numeric")
dataSet.add_parameters([parameter_a])
dataSet.add_result({"a": np.int32(1)})

print(dataSet.get_data("a"))
```
The output is 

```python
[[b'\x01\x00\x00\x00']]
```

We need to make correct converters for numpy types. 


Discussion:

Resolving patch:
diff --git a/qcodes/dataset/sqlite_base.py b/qcodes/dataset/sqlite_base.py
--- a/qcodes/dataset/sqlite_base.py
+++ b/qcodes/dataset/sqlite_base.py
@@ -197,6 +197,16 @@ def connect(name: str, debug: bool = False) -> sqlite3.Connection:
     # sqlite3 options
     conn.row_factory = sqlite3.Row
 
+    # Make sure numpy ints and floats types are inserted properly
+    for numpy_int in [
+        np.int, np.int8, np.int16, np.int32, np.int64,
+        np.uint, np.uint8, np.uint16, np.uint32, np.uint64
+    ]:
+        sqlite3.register_adapter(numpy_int, int)
+
+    for numpy_float in [np.float, np.float16, np.float32, np.float64]:
+        sqlite3.register_adapter(numpy_float, float)
+
     if debug:
         conn.set_trace_callback(print)
     return conn


Test patch:
diff --git a/qcodes/tests/dataset/test_dataset_basic.py b/qcodes/tests/dataset/test_dataset_basic.py
--- a/qcodes/tests/dataset/test_dataset_basic.py
+++ b/qcodes/tests/dataset/test_dataset_basic.py
@@ -328,3 +328,35 @@ def test_database_upgrade(empty_temp_db):
 
     atomicTransaction(connection, sql)
     set_user_version(connection, 1)
+
+
+def test_numpy_ints(dataset):
+    """
+     Test that we can insert numpy integers in the data set
+    """
+    xparam = ParamSpec('x', 'numeric')
+    dataset.add_parameters([xparam])
+
+    numpy_ints = [
+        np.int, np.int8, np.int16, np.int32, np.int64,
+        np.uint, np.uint8, np.uint16, np.uint32, np.uint64
+    ]
+
+    results = [{"x": tp(1)} for tp in numpy_ints]
+    dataset.add_results(results)
+    expected_result = len(numpy_ints) * [[1]]
+    assert dataset.get_data("x") == expected_result
+
+
+def test_numpy_floats(dataset):
+    """
+    Test that we can insert numpy floats in the data set
+    """
+    float_param = ParamSpec('y', 'numeric')
+    dataset.add_parameters([float_param])
+
+    numpy_floats = [np.float, np.float16, np.float32, np.float64]
+    results = [{"y": tp(1.2)} for tp in numpy_floats]
+    dataset.add_results(results)
+    expected_result = [[tp(1.2)] for tp in numpy_floats]
+    assert dataset.get_data("y") == expected_result
Repository: microsoft/Qcodes

Issue:
Bug in ramp_rate for AMI430 driver
### Bug

The following code (where ix is an AMI430 driver):
`ix.ramp_rate(0.001)`

produces an error:
`TypeError: ("'str' object is not callable", 'setting ix_ramp_rate to 0.001')`

### Proposed fix

In instrument_drivers/american_magnetics/AMI430.py line 367, change:
`raise ValueError(f"{rate} {self.ramp_rate.unit()} "`

to:
`raise ValueError(f"{rate} {self.ramp_rate.unit} "`



Discussion:
Thanks for pointing that out, I agree that it seems to be the correct fix.

Resolving patch:
diff --git a/qcodes/instrument_drivers/american_magnetics/AMI430.py b/qcodes/instrument_drivers/american_magnetics/AMI430.py
--- a/qcodes/instrument_drivers/american_magnetics/AMI430.py
+++ b/qcodes/instrument_drivers/american_magnetics/AMI430.py
@@ -364,7 +364,7 @@ def _get_ramp_rate(self):
     def _set_ramp_rate(self, rate):
         """ Set the ramp rate of the first segment in Tesla per second """
         if rate > self.field_ramp_limit():
-            raise ValueError(f"{rate} {self.ramp_rate.unit()} "
+            raise ValueError(f"{rate} {self.ramp_rate.unit} "
                              f"is above the ramp rate limit of "
                              f"{self.field_ramp_limit()} "
                              f"{self.field_ramp_limit()}")


Test patch:
Repository: microsoft/Qcodes

Issue:
Creation of db files when import qcodes
It's not a bug I guess, but I think its still unwanted. 

### Steps to reproduce
Set any directory to the current working directory
Execute a python script/program that just imports the qcodes module

### Expected behaviour
No side-effects of the file system

### Actual behaviour
An experiment.db file is created in the current working directory. 

I think it's better if measurement databases are only created when we actually call a function that initialized an experiment. 
I use the qcodes module to load my experimental data from a lot of different working directories, like folders where I work on papers, during the analyses, etc... 


Discussion:

Resolving patch:
diff --git a/qcodes/__init__.py b/qcodes/__init__.py
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -77,15 +77,6 @@
     load_last_experiment, experiments
 from qcodes.dataset.sqlite_settings import SQLiteSettings
 from qcodes.dataset.param_spec import ParamSpec
-# TODO: do we want this?
-from qcodes.dataset.sqlite_base import connect as _connect
-from qcodes.dataset.sqlite_base import init_db as _init_db
-
-_c = _connect(config["core"]["db_location"], config["core"]["db_debug"])
-# init is actually idempotent so it's safe to always call!
-_init_db(_c)
-_c.close()
-del _c
 
 try:
     get_ipython() # type: ignore # Check if we are in iPython
diff --git a/qcodes/dataset/database.py b/qcodes/dataset/database.py
--- a/qcodes/dataset/database.py
+++ b/qcodes/dataset/database.py
@@ -1,12 +1,14 @@
 # high-level interface to the database
 
+from os.path import expanduser
+
 from qcodes.dataset.sqlite_base import connect as _connect
 from qcodes.dataset.sqlite_base import init_db as _init_db
 import qcodes.config
 
 
 def get_DB_location() -> str:
-    return qcodes.config["core"]["db_location"]
+    return expanduser(qcodes.config["core"]["db_location"])
 
 
 def get_DB_debug() -> bool:


Test patch:
diff --git a/qcodes/tests/drivers/test_tektronix_AWG70000A.py b/qcodes/tests/drivers/test_tektronix_AWG70000A.py
--- a/qcodes/tests/drivers/test_tektronix_AWG70000A.py
+++ b/qcodes/tests/drivers/test_tektronix_AWG70000A.py
@@ -94,7 +94,7 @@ def test_init_awg2(awg2):
     assert idn_dict['vendor'] == 'QCoDeS'
 
 
-@settings(deadline=1500, max_examples=7)
+@settings(deadline=2500, max_examples=7)
 @given(N=hst.integers(1, 100))
 def test_SML_successful_generation_vary_length(N):
Repository: microsoft/Qcodes

Issue:
np.nan removed when using the context manager
To reproduce: 
```python
import numpy as np
from numpy import ndarray

from qcodes import ParamSpec, new_data_set, new_experiment
from qcodes.dataset.measurements import Measurement
from qcodes.dataset.data_export import get_data_by_id

from qcodes.dataset.experiment_container import new_experiment

new_experiment("nan_types", "nan")

meas.register_custom_parameter(
    name="x", unit="V"
)

meas.register_custom_parameter(
    name="m", unit="I", setpoints=("x",)
)

with meas.run() as datasaver:
    datasaver.add_result(("x", [0, 1, 2]), ("m", np.array([0.0, np.nan, 1.0])))

dataset = get_data_by_id(datasaver.run_id)
```
If we inspect the dataset we will see that the np.nan has been removed entirely. This is unacceptable, especially in 2D datasets as it will prevent us from plotting the data in the usual manner. 


Discussion:

Resolving patch:
diff --git a/qcodes/dataset/sqlite_base.py b/qcodes/dataset/sqlite_base.py
--- a/qcodes/dataset/sqlite_base.py
+++ b/qcodes/dataset/sqlite_base.py
@@ -108,6 +108,19 @@ def _convert_array(text: bytes) -> ndarray:
     return np.load(out)
 
 
+def _convert_numeric(value: bytes) -> Union[float, int]:
+    numeric = float(value)
+    if np.isnan(numeric) or numeric != int(numeric):
+        return numeric
+    return int(numeric)
+
+
+def _adapt_float(fl: float) -> Union[float, str]:
+    if np.isnan(fl):
+        return "nan"
+    return float(fl)
+
+
 def one(curr: sqlite3.Cursor, column: Union[int, str]) -> Any:
     """Get the value of one column from one row
     Args:
@@ -188,8 +201,10 @@ def connect(name: str, debug: bool = False) -> sqlite3.Connection:
     ]:
         sqlite3.register_adapter(numpy_int, int)
 
+    sqlite3.register_converter("numeric", _convert_numeric)
+
     for numpy_float in [np.float, np.float16, np.float32, np.float64]:
-        sqlite3.register_adapter(numpy_float, float)
+        sqlite3.register_adapter(numpy_float, _adapt_float)
 
     if debug:
         conn.set_trace_callback(print)


Test patch:
diff --git a/qcodes/tests/dataset/test_dataset_basic.py b/qcodes/tests/dataset/test_dataset_basic.py
--- a/qcodes/tests/dataset/test_dataset_basic.py
+++ b/qcodes/tests/dataset/test_dataset_basic.py
@@ -361,4 +361,14 @@ def test_numpy_floats(dataset):
     results = [{"y": tp(1.2)} for tp in numpy_floats]
     dataset.add_results(results)
     expected_result = [[tp(1.2)] for tp in numpy_floats]
-    assert dataset.get_data("y") == expected_result
+    assert np.allclose(dataset.get_data("y"), expected_result, atol=1E-8)
+
+
+def test_numpy_nan(dataset):
+    parameter_m = ParamSpec("m", "numeric")
+    dataset.add_parameters([parameter_m])
+
+    data_dict = [{"m": value} for value in [0.0, np.nan, 1.0]]
+    dataset.add_results(data_dict)
+    retrieved = dataset.get_data("m")
+    assert np.isnan(retrieved[1])
Repository: microsoft/Qcodes

Issue:
SR86x driver does not allow amplitude set to 0
### Steps to reproduce
1. try runnning `lockin.amplitude(0)`

### Expected behaviour
Lockin amplitude should be set to 0

### Actual behaviour
Validation error is thrown, driver has a minimum amplitude of 10e-9V



Discussion:

Resolving patch:
diff --git a/qcodes/instrument_drivers/stanford_research/SR86x.py b/qcodes/instrument_drivers/stanford_research/SR86x.py
--- a/qcodes/instrument_drivers/stanford_research/SR86x.py
+++ b/qcodes/instrument_drivers/stanford_research/SR86x.py
@@ -338,7 +338,7 @@ def __init__(self, name, address, max_frequency, reset=False, **kwargs):
                            get_cmd='SLVL?',
                            set_cmd='SLVL {}',
                            get_parser=float,
-                           vals=Numbers(min_value=10e-9, max_value=2))
+                           vals=Numbers(min_value=0, max_value=2))
         self.add_parameter(name='harmonic',
                            label='Harmonic',
                            get_cmd='HARM?',


Test patch:
Repository: microsoft/Qcodes

Issue:
AWG 5208 behavior in play()
in the AWG70000A driver, when we call 'play', the behavior is this (line 493):
`running = self.run_state() == 'Running'`
this is a bit odd for the case where the sequence starts with an element that will result in wait for trigger.
I think this should be changed to:
`running = self.run_state() in ['Running', 'Waiting for trigger']`
to capture all possibilities where the instrument is in principle ready to go.


Discussion:

Resolving patch:
diff --git a/qcodes/instrument_drivers/tektronix/AWG70000A.py b/qcodes/instrument_drivers/tektronix/AWG70000A.py
--- a/qcodes/instrument_drivers/tektronix/AWG70000A.py
+++ b/qcodes/instrument_drivers/tektronix/AWG70000A.py
@@ -490,7 +490,8 @@ def play(self, wait_for_running: bool=True, timeout: float=10) -> None:
             running = False
             while not running:
                 time.sleep(0.1)
-                running = self.run_state() == 'Running'
+                running = self.run_state() in ('Running',
+                                               'Waiting for trigger')
                 waited_for = start_time - time.perf_counter()
                 if waited_for > timeout:
                     raise RuntimeError(f'Reached timeout ({timeout} s) '


Test patch:
Repository: microsoft/Qcodes

Issue:
Bug in config
Please forgive me if I am wrong (I am not), but should this not be `self.current_config` ?

https://github.com/QCoDeS/Qcodes/blob/ffc6f068f1504ddf0aa5a8657747b4583fbd55bb/qcodes/config/config.py#L393-L399



Discussion:
@tomasstankevic thanks for reporting this. I'll make a PR with a fix shortly.

Resolving patch:
diff --git a/qcodes/config/config.py b/qcodes/config/config.py
--- a/qcodes/config/config.py
+++ b/qcodes/config/config.py
@@ -355,12 +355,13 @@ def save_to_cwd(self):
         self.save_config(self.cwd_file_name)
         self.save_schema(self.schema_cwd_file_name)
 
-    def describe(self, name):
+    def describe(self, name: str) -> str:
         """
         Describe a configuration entry
 
         Args:
-            name (str): name of entry to describe
+            name: name of entry to describe in 'dotdict' notation,
+              e.g. name="user.scriptfolder"
         """
         val = self.current_config
         sch = self.current_schema["properties"]
@@ -392,9 +393,9 @@ def __getattr__(self, name):
 
     def __repr__(self):
         old = super().__repr__()
-        output = f"""Current values: \n {current_config} \n
-                     Current paths: \n {self._loaded_config_files} \n
-                     {old}"""
+        output = (f"Current values: \n {self.current_config} \n"
+                  f"Current paths: \n {self._loaded_config_files} \n"
+                  f"{old}")
         return output
 
 


Test patch:
diff --git a/qcodes/tests/test_config.py b/qcodes/tests/test_config.py
--- a/qcodes/tests/test_config.py
+++ b/qcodes/tests/test_config.py
@@ -325,3 +325,38 @@ def test_update_from_path(path_to_config_file_on_disk):
         expected_path = os.path.join(path_to_config_file_on_disk,
                                      'qcodesrc.json')
         assert cfg.current_config_path == expected_path
+
+
+def test_repr():
+    cfg = Config()
+    rep = cfg.__repr__()
+
+    expected_rep = (f"Current values: \n {cfg.current_config} \n"
+                    f"Current paths: \n {cfg._loaded_config_files} \n"
+                    f"{super(Config, cfg).__repr__()}")
+
+    assert rep == expected_rep
+
+
+def test_add_and_describe():
+    """
+    Test that a key an be added and described
+    """
+    with default_config():
+
+        key = 'newkey'
+        value ='testvalue'
+        value_type ='string'
+        description ='A test'
+        default = 'testdefault'
+
+        cfg = Config()
+        cfg.add(key=key, value=value, value_type=value_type,
+                description=description, default=default)
+
+
+        desc = cfg.describe(f'user.{key}')
+        expected_desc = (f"{description}.\nCurrent value: {value}. "
+                         f"Type: {value_type}. Default: {default}.")
+
+        assert desc == expected_desc
Repository: microsoft/Qcodes

Issue:
get_shaped_data_by_runid does not reshape data
### Steps to reproduce
1. use function with qc_run_id corresponding to a 2D dataset
2. print shapes of array and see they are all 1D

### Expected behaviour
Expecting 2D np arrays to be returned

### Potential fix
datatype_from_setpoints_2d seem to return datatypes wit '2D' appended to them, i.e '2D_grid' as opposed to 'grid' as get_shaped_data_by_runid expects it.





Discussion:

Resolving patch:
diff --git a/qcodes/dataset/data_export.py b/qcodes/dataset/data_export.py
--- a/qcodes/dataset/data_export.py
+++ b/qcodes/dataset/data_export.py
@@ -424,7 +424,7 @@ def get_shaped_data_by_runid(run_id: int) -> List:
 
             datatype = datatype_from_setpoints_2d(independet[0]['data'],
                                                   independet[1]['data'])
-            if datatype in ('grid', 'equidistant'):
+            if datatype in ('2D_grid', '2D_equidistant'):
                 independet[0]['data'], \
                 independet[1]['data'], \
                 independet[2]['data'] = reshape_2D_data(independet[0]['data'],


Test patch:
Repository: microsoft/Qcodes

Issue:
QCoDeS monitor broken on master
The qcodes monitor is broken on the latest master. The error is occuring somewhere in the javascript as the data is still correctly sent over the websocket.

### Steps to reproduce
1. Create a monitor in QCoDeS.
2. Launch the monitor using `python -m qcodes.monitor.monitor`

### Expected behaviour
QCoDeS monitor displays in webbrowser.

### Actual behaviour
I get an error message in both Firefox and IE. (I don't have a copy of chrome to test on my experimental PC.

The error is: 
```
Status:error:I ran into the following problems at _.parameters[0].parameters[34].ts: Expecting null but instead got: "1581406601.743032" Expecting a Float but instead got: "1581406601.743032"
```

The issue seems to have crept in between revisions e5c5324 and 1ce7a23.

I've attached a sample response from the websocket in the working state and the broken state, where you can see that the timestamp is being sent as a string instead of a float...

[websocket_brokensample.txt](https://github.com/QCoDeS/Qcodes/files/4184596/websocket_brokensample.txt)
[websocket_workingsample.txt](https://github.com/QCoDeS/Qcodes/files/4184597/websocket_workingsample.txt)

### System
Windows 10
QCodes Master 33d4e71



Discussion:
Looks like the error is here: 76c34f1

The timestamp is being converted to a string in the `_get_metadata` function of `monitor.py` and is not parsed correctly on the frontend.

Resolving patch:
diff --git a/qcodes/monitor/monitor.py b/qcodes/monitor/monitor.py
--- a/qcodes/monitor/monitor.py
+++ b/qcodes/monitor/monitor.py
@@ -26,7 +26,7 @@
 import time
 import json
 from contextlib import suppress
-from typing import Dict, Any, Optional, Sequence, Callable, Awaitable
+from typing import Dict, Union, Any, Optional, Sequence, Callable, Awaitable
 from collections import defaultdict
 
 import asyncio
@@ -61,11 +61,11 @@ def _get_metadata(*parameters: Parameter) -> Dict[str, Any]:
     for parameter in parameters:
         # Get the latest value from the parameter,
         # respecting the max_val_age parameter
-        meta: Dict[str, Optional[str]] = {}
+        meta: Dict[str, Optional[Union[float, str]]] = {}
         meta["value"] = str(parameter.get_latest())
         timestamp = parameter.get_latest.get_timestamp()
         if timestamp is not None:
-            meta["ts"] = str(timestamp.timestamp())
+            meta["ts"] = timestamp.timestamp()
         else:
             meta["ts"] = None
         meta["name"] = parameter.label or parameter.name


Test patch: