Skip to content

Commit

Permalink
- adds IKAWA PRO X machine support (records ambient pressure, humidit…
Browse files Browse the repository at this point in the history
…y and inlet temperature)

- records filtered data from IKAWA if unfiltered data is not available
- adds logging of startup datetime to catch the year
- fixes RoR axis redraw on toggle the visibility of BT/ET RoR curves
- adds cache holding LCD visibility
- updates libs
  • Loading branch information
MAKOMO committed Jan 18, 2024
1 parent 35bfbea commit 1a071cf
Show file tree
Hide file tree
Showing 44 changed files with 49,121 additions and 49,002 deletions.
199 changes: 112 additions & 87 deletions src/artisanlib/canvas.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/artisanlib/comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1717,8 +1717,9 @@ def Ikawa_State(self) -> Tuple[float,float,float]:
t1:float = -1
t2:float = -1
if self.aw.ikawa is not None:
t1 = self.aw.ikawa.absolute_humidity
t2 = self.aw.ikawa.state
return tx,t1,t2 # time, _ (chan2), State (chan1)
return tx,t1,t2 # time, Absolute Humidity [g/m^3] (chan2), State (chan1)

def TEVA18B(self) -> Tuple[float,float,float]:
tx = self.aw.qmc.timeclock.elapsedMilli()
Expand Down
4 changes: 3 additions & 1 deletion src/artisanlib/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -2277,10 +2277,12 @@ def changeDecimalPlaceslcd(self) -> None:

@pyqtSlot(int)
def changeDeltaBT(self, _:int = 0) -> None:
twoAxis_before = self.aw.qmc.twoAxisMode()
self.aw.qmc.DeltaBTflag = not self.aw.qmc.DeltaBTflag
twoAxis_after = self.aw.qmc.twoAxisMode()
if self.aw.qmc.crossmarker:
self.aw.qmc.togglecrosslines() # turn crossmarks off to adjust for new coordinate system
self.aw.qmc.redraw_keep_view(recomputeAllDeltas=True)
self.aw.qmc.redraw_keep_view(recomputeAllDeltas=True, forceRenewAxis=(twoAxis_before != twoAxis_after))

@pyqtSlot(int)
def changeDeltaETlcd(self, _:int = 0) -> None:
Expand Down
98 changes: 73 additions & 25 deletions src/artisanlib/ikawa.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import csv
import re
import logging
from typing import Final, Optional, List, Tuple, Callable, ClassVar, Any, Generator, TYPE_CHECKING
from typing import Final, Optional, List, Dict, Tuple, Callable, ClassVar, Any, Generator, TYPE_CHECKING


if TYPE_CHECKING:
Expand Down Expand Up @@ -179,7 +179,7 @@ def extractProfileIkawaCSV(file:str, aw:'ApplicationWindow') -> 'ProfileData':
with open(file, newline='',encoding='utf-8') as csvFile:
data = csv.reader(csvFile,delimiter=',')
#read file header
header = next(data)
header = [h.strip() for h in next(data)]

fan:Optional[float] = None # holds last processed fan event value
fan_last:Optional[float] = None # holds the fan event value before the last one
Expand All @@ -203,12 +203,14 @@ def extractProfileIkawaCSV(file:str, aw:'ApplicationWindow') -> 'ProfileData':
timeindex:List[int] = [-1,0,0,0,0,0,0,0] #CHARGE index init set to -1 as 0 could be an actual index used
i:int = 0
v:Optional[float]
last_item:Optional[Dict[str,str]] = None
for row in data:
i = i + 1
items = list(zip(header, row))
item = {}
item:Dict[str,str] = {}
for (name, value) in items:
item[name] = value.strip()
last_item = item
# take i as time in seconds
timex.append(i)
if 'inlet temp' in item:
Expand Down Expand Up @@ -248,7 +250,11 @@ def extractProfileIkawaCSV(file:str, aw:'ApplicationWindow') -> 'ProfileData':
extra3.append(-1)
extra4.append(-1)
extra5.append(-1)
extra6.append(-1)
if 'abs_humidity' in item:
humidity = float(item['abs_humidity'])
extra6.append(humidity)
else:
extra6.append(-1)

if 'fan set (%)' in item or 'fan set' in item:
try:
Expand Down Expand Up @@ -312,6 +318,15 @@ def extractProfileIkawaCSV(file:str, aw:'ApplicationWindow') -> 'ProfileData':
heater_last = None
except Exception as e: # pylint: disable=broad-except
_log.exception(e)
if last_item is not None and timeindex[0]>-1 and 'adfc_timestamp' in last_item:
# if there is data at all, CHARGE is set and adfc_timestamp is given
# fcs_time is the time of FCs in seconds after CHARGE
fcs_time = float(last_item['adfc_timestamp'])
if fcs_time > 0:
# if fcs_time is given
FCs_idx = int(round(fcs_time + timeindex[0]))
if 0 < FCs_idx < len(timex):
timeindex[2] = FCs_idx

res['mode'] = 'C'

Expand All @@ -327,7 +342,7 @@ def extractProfileIkawaCSV(file:str, aw:'ApplicationWindow') -> 'ProfileData':
res['extratemp1'] = [extra1, extra3, extra5]
res['extramathexpression1'] = ['', '', '']

res['extraname2'] = ['RPM', '{0}', 'Extra 2']
res['extraname2'] = ['RPM', '{0}', 'Humidity']
res['extratemp2'] = [extra2, extra4, extra6]
res['extramathexpression2'] = ['x/100', '', '']

Expand Down Expand Up @@ -386,17 +401,22 @@ def __init__(self,
self.heater:int = -1
self.fan:int = -1
self.state:int = -1
self.absolute_humidity:float = -1
self.ambient_pressure:float = -1
self.board_temp:float = -1
# state is one of
# 0: on-roaster
# 0: on-roaster (IDLE)
# 1: pre-heating (START)
# 2: ready-to-roast
# 3: roasting
# 4: roaster-is-busy
# 4: roaster-is-busy (BUSY)
# 5: cooling (DROP)
# 6: doser-open (CHARGE)
# 7: unexpected-problem
# 7: unexpected-problem (ERROR)
# 8: ready-to-blow
# 9: test-mode
# 10: detecting
# 11: development

self.seq:Generator[int, None, None] = self.seqNum() # message sequence number generator

Expand Down Expand Up @@ -466,6 +486,9 @@ def clearData(self) -> None:
self.heater = -1
self.fan = -1
self.state = -1
self.absolute_humidity = -1
self.ambient_pressure = -1
self.board_temp = -1

def reset(self) -> None:
self.rcv_buffer = None
Expand Down Expand Up @@ -509,23 +532,48 @@ def processData(self, _write:Callable[[Optional[bytes]],None], data:bytes) -> Tu
if crc == self.crc16(payload, 65535):
try:
decoded_message = IkawaCmd_pb2.IkawaResponse().FromString(payload) # pylint: disable=no-member
_log.debug('IKAWA response.resp: %s (%s)', decoded_message.resp, decoded_message.MACH_STATUS_GET_ALL)
status_get_all = decoded_message.resp_mach_status_get_all
self.ET = status_get_all.temp_below / 10
if self.ET == 0:
self.ET = -1
self.BT = status_get_all.temp_above / 10
if self.BT == 0:
self.BT = -1
self.SP = status_get_all.setpoint / 10
if self.SP == 0:
self.SP = -1
self.RPM = (status_get_all.fan_measured / 12)*60 # RPM
self.heater = status_get_all.heater * 2
self.fan = int(round(status_get_all.fan / 2.55))
self.state = status_get_all.state
# add data received and registered, enable delivery
self.dataReceived.wakeAll()
if decoded_message.HasField('resp_mach_status_get_all'):
_log.debug('IKAWA response.resp: %s (%s)', decoded_message.resp, decoded_message.MACH_STATUS_GET_ALL)
status_get_all = decoded_message.resp_mach_status_get_all
# temp below is Inlet Temperature on PRO machines and Exaust Temperature on HOME machines
if status_get_all.HasField('temp_below'):
self.ET = status_get_all.temp_below / 10
elif status_get_all.HasField('temp_below_filtered'):
self.ET = status_get_all.temp_below_filtered / 10
else:
self.ET = -1
if status_get_all.HasField('temp_above'):
self.BT = status_get_all.temp_above / 10
elif status_get_all.HasField('temp_above_filtered'):
self.BT = status_get_all.temp_above_filtered / 10
else:
self.BT = -1
if status_get_all.HasField('setpoint'):
self.SP = status_get_all.setpoint / 10
else:
self.SP = -1
if status_get_all.HasField('fan_measured'):
self.RPM = (status_get_all.fan_measured / 12)*60 # RPM
else:
self.RPM = -1
self.heater = status_get_all.heater * 2
self.fan = int(round(status_get_all.fan / 2.55))
self.state = status_get_all.state
# compute the average of all received ambient pressure readings (in mbar)
if status_get_all.HasField('pressure_amb'):
self.ambient_pressure = (status_get_all.pressure_amb if self.ambient_pressure == -1 else (self.ambient_pressure + status_get_all.pressure_amb)/2)
# add absolute humidity in g/m^3
if status_get_all.HasField('humidity_abs'):
self.absolute_humidity = status_get_all.humidity_abs / 100
else:
self.absolute_humidity = -1
# add board temperature in C
if status_get_all.HasField('humidity_abs'):
self.board_temp = status_get_all.board_temp / 10
else:
self.board_temp = -1
# add data received and registered, enable delivery
self.dataReceived.wakeAll()
except Exception as e: # pylint: disable=broad-except
_log.error(e)
else:
Expand Down
13 changes: 8 additions & 5 deletions src/artisanlib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,9 @@ def permissionUpdated(permission:'QPermission') -> None:
str(__revision__),
str(__build__),
)
_log.info('platform: %s',str(platform.platform()))
_log.info('exec: %s', str(sys.executable))
_log.info('date: %s', datetime.datetime.now(datetime.timezone.utc))
_log.info('platform: %s',platform.platform())
_log.info('exec: %s', sys.executable)
else:
_log.info('child process loaded')

Expand Down Expand Up @@ -4142,11 +4143,13 @@ def toggleDeltaETCurve(self) -> None:

@pyqtSlot()
def toggleDeltaBTCurve(self) -> None:
twoAxis_before = self.qmc.twoAxisMode()
if self.qmc.swapdeltalcds:
self.qmc.DeltaETflag = not self.qmc.DeltaETflag
else:
self.qmc.DeltaBTflag = not self.qmc.DeltaBTflag
self.qmc.redraw_keep_view(recomputeAllDeltas=False)
twoAxis_after = self.qmc.twoAxisMode()
self.qmc.redraw_keep_view(recomputeAllDeltas=False,forceRenewAxis=(twoAxis_before != twoAxis_after))

@pyqtSlot()
def toggleExtraCurve1(self) -> None:
Expand Down Expand Up @@ -14166,11 +14169,11 @@ def setProfile(self, filename:Optional[str], profile:'ProfileData', quiet:bool =

# Shift+Alt modifier allows to overwrite extra devices (as was default in v2.4.6)
if QApplication.queryKeyboardModifiers() == Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.ShiftModifier:
string = QApplication.translate("Message","To fully load this profile the extra device configuration needs to be modified.\n\nOverwrite your extra device definitions using the values from the profile?\n\nIt is advisable to save your current settings beforehand via menu Help >> Save Settings.")
string = QApplication.translate('Message','To fully load this profile the extra device configuration needs to be modified.\n\nOverwrite your extra device definitions using the values from the profile?\n\nIt is advisable to save your current settings beforehand via menu Help >> Save Settings.')
if quiet:
reply = QMessageBox.StandardButton.Yes
else:
reply = QMessageBox.question(self, QApplication.translate("Message", "Found a different set of extra devices"), string,
reply = QMessageBox.question(self, QApplication.translate('Message', 'Found a different set of extra devices'), string,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.No)

if reply == QMessageBox.StandardButton.Yes:
Expand Down
3 changes: 2 additions & 1 deletion src/artisanlib/modbusport.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ def connect(self) -> None:
self.readRetries = self.serial_readRetries
_log.debug('connect(): connecting')
time.sleep(.2) # avoid possible hickups on startup
self.master.connect() # type:ignore[no-untyped-call]
if self.master is not None:
self.master.connect() # type:ignore[no-untyped-call]
if self.isConnected():
self.updateActiveRegisters()
self.clearReadingsCache()
Expand Down
8 changes: 4 additions & 4 deletions src/includes/Machines/IKAWA/HOME.aset
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[General]
Delay=1000
dropDuplicates=true
dropDuplicatesLimit=0.19999999999999998
dropDuplicatesLimit=0.2
roasterheating_setup=3
roastertype_setup=IKAWA HOME
roastersize_setup_default=0.1
Expand Down Expand Up @@ -43,16 +43,16 @@ extratimeout=0.4, 0.4, 0.4

[ExtraDev]
devicetablecolumnwidths=154, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100
extraCurveVisibility1=true, true, false, true, true, true, true, true, true, true
extraCurveVisibility1=true, false, false, true, true, true, true, true, true, true
extraCurveVisibility2=true, false, false, true, true, true, true, true, true, true
extraDelta1=false, false, false, false, false, false, false, false, false, false
extraDelta2=false, false, false, false, false, false, false, false, false, false
extraFill1=0, 0, 0, 0, 0, 0, 0, 0, 0, 0
extraFill2=0, 0, 0, 0, 0, 0, 0, 0, 0, 0
extraLCDvisibility1=true, true, false, false, false, false, false, false, false, false
extraLCDvisibility2=true, true, false, false, false, false, false, false, false, false
extradevicecolor1=#ff5d00, #650067, black
extradevicecolor2=#33983c, #45a6cf, black
extradevicecolor1=#ff5d00, #AD0628, black
extradevicecolor2=#33983c, #45a6cf, #650067
extradevices=143, 144, 145
extramathexpression1=, ,
extramathexpression2=x/100, ,
Expand Down
13 changes: 8 additions & 5 deletions src/includes/Machines/IKAWA/PRO.aset
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
[General]
Delay=1000
dropDuplicates=true
dropDuplicatesLimit=0.19999999999999998
dropDuplicatesLimit=0.2
roasterheating_setup=3
roastertype_setup=IKAWA PRO
roastersize_setup_default=0.1
BTcurve=true
BTlcd=true
BTBflag=true
curvefilter=1

[Alarms]
Expand Down Expand Up @@ -40,21 +43,21 @@ extratimeout=0.4, 0.4, 0.4

[ExtraDev]
devicetablecolumnwidths=154, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100
extraCurveVisibility1=true, true, false, true, true, true, true, true, true, true
extraCurveVisibility1=true, false, false, true, true, true, true, true, true, true
extraCurveVisibility2=true, false, false, true, true, true, true, true, true, true
extraDelta1=false, false, false, false, false, false, false, false, false, false
extraDelta2=false, false, false, false, false, false, false, false, false, false
extraFill1=0, 0, 0, 0, 0, 0, 0, 0, 0, 0
extraFill2=0, 0, 0, 0, 0, 0, 0, 0, 0, 0
extraLCDvisibility1=true, true, false, false, false, false, false, false, false, false
extraLCDvisibility2=true, true, false, false, false, false, false, false, false, false
extradevicecolor1=#ff5d00, #650067, black
extradevicecolor2=#33983c, #45a6cf, black
extradevicecolor1=#ff5d00, #AD0628, black
extradevicecolor2=#33983c, #45a6cf, #650067
extradevices=143, 144, 145
extramathexpression1=, ,
extramathexpression2=x/100, ,
extraname1=SET, {3}, State
extraname2=RPM, {0}, Extra 2
extraname2=RPM, {0}, -

[Quantifiers]
clusterEventsFlag=false
Expand Down
57 changes: 31 additions & 26 deletions src/proto/IkawaCmd.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,37 @@ message IkawaResponse {

}

message RespMachStatusGetAll{
required int32 time = 1;
optional int32 temp_above = 2;
required int32 fan = 3;
required int32 state = 4;
required int32 heater = 5;
required int32 p = 6;
required int32 i = 7;
required int32 d = 8;
required int32 setpoint = 9;
required int32 fan_measured = 10;
optional int32 board_temp = 11;
optional int32 temp_below = 12;
optional int32 fan_rpm_measured = 13;
optional int32 fan_rpm_setpoint = 14;
optional int32 fan_i = 16;
optional int32 fan_p = 15;
optional int32 fan_d = 17;
optional int32 fan_power = 18;
optional int32 j = 19;
optional int32 relay_state = 20;
optional int32 pid_sensor = 21;
optional int32 temp_above_filtered = 22;
optional int32 temp_below_filtered = 23;
optional int32 ror_above = 24;
optional int32 ror_below = 25;
message RespMachStatusGetAll {
required uint32 time = 1;
optional uint32 temp_above = 2;
optional uint32 temp_below = 12;
required uint32 fan = 3;
// The measured fan speed
optional uint32 fan_measured = 10;
required uint32 state = 4;
required uint32 heater = 5;
required uint32 p = 6;
required uint32 i = 7;
required uint32 d = 8;
optional sint32 j = 19;
required uint32 setpoint = 9;
optional uint32 board_temp = 11;
optional uint32 fan_rpm_measured = 13;
optional uint32 fan_rpm_setpoint = 14;
optional sint32 fan_p = 15;
optional sint32 fan_i = 16;
optional sint32 fan_d = 17;
optional uint32 fan_power = 18;
optional uint32 relay_state = 20;
optional uint32 pid_sensor = 21;
optional uint32 temp_above_filtered = 22;
optional uint32 temp_below_filtered = 23;
optional sint32 ror_above = 24;
optional sint32 ror_below = 25;
optional uint32 humidity_abs = 26;
optional sint32 humidity_roc = 27;
optional uint32 humidity_roc_direction = 28;
optional uint32 pressure_amb = 29;
}

message RespMachStatusGetError{
Expand Down
Loading

0 comments on commit 1a071cf

Please sign in to comment.