diff --git a/lib/WebSocket.dart b/lib/WebSocket.dart index 5d324912..97338e79 100644 --- a/lib/WebSocket.dart +++ b/lib/WebSocket.dart @@ -12,15 +12,22 @@ enum WebSocketState { disconnected, connecting, connected, error } class WebSocketWrapper { final _logger = getLogger('WebSocketWrapper'); - final int defaultMaxRetries; - final Duration _defaultTimeout; + + int tries = 0; + String url; - IOWebSocketChannel? _channel; + String? apiKey; - WebSocketWrapper(this.url, this._defaultTimeout, - {this.defaultMaxRetries = 3, this.apiKey}) { - this.initCommunication(defaultMaxRetries); + IOWebSocketChannel? _channel; + + final Duration _defaultTimeout; + + Map _headers = {}; + + WebSocketWrapper(this.url, this._defaultTimeout, {this.apiKey}) { + if (apiKey != null) _headers['X-Api-Key'] = apiKey; + this.initCommunication(); } BehaviorSubject stateStream = @@ -29,7 +36,7 @@ class WebSocketWrapper { WebSocketState get state => stateStream.value; set state(WebSocketState newState) { - _logger.i("WebSocket: $state ➝ $newState"); + _logger.i("$state ➝ $newState"); stateStream.add(newState); } @@ -53,22 +60,21 @@ class WebSocketWrapper { /// ---------------------------------------------------------- /// Initialization the WebSockets connection with the server /// ---------------------------------------------------------- - initCommunication([int? tries]) { - _tryConnect(tries ?? defaultMaxRetries); + initCommunication() { + _tryConnect(); } - _tryConnect(int maxRetries) { - _logger.i("Trying to connect to $url with APIkey: `$apiKey`"); + _tryConnect() { + _logger.i("Trying to connect to $url with APIkey: `${apiKey??'NO-APIKEY'}`"); state = WebSocketState.connecting; reset(); - Map headers = {}; - if (apiKey != null) headers['X-Api-Key'] = apiKey; - WebSocket.connect(url.toString(), headers: headers) + WebSocket.connect(url.toString(), headers: _headers) .timeout(_defaultTimeout) .then((socket) { socket.pingInterval = _defaultTimeout; _channel = IOWebSocketChannel(socket); + tries = 0; /// /// Start listening to notifications / messages @@ -76,7 +82,7 @@ class WebSocketWrapper { _channel!.stream.listen( _onWSMessage, onError: _onWSError, - onDone: () => _onWSClosesNormal(maxRetries), + onDone: () => _onWSClosesNormal(), ); // Send a req msg to be sure we are connected! @@ -185,12 +191,13 @@ class WebSocketWrapper { return false; } - _onWSClosesNormal(int maxRetries) { + _onWSClosesNormal() { var t = state; if (t != WebSocketState.error) { t = WebSocketState.disconnected; } if (!stateStream.isClosed) state = t; + initCommunication(); _logger.i("WS-Stream close normal!"); } } diff --git a/lib/dto/config/ConfigFile.dart b/lib/dto/config/ConfigFile.dart index 7441d864..0c8aab6a 100644 --- a/lib/dto/config/ConfigFile.dart +++ b/lib/dto/config/ConfigFile.dart @@ -53,11 +53,22 @@ class ConfigExtruder { } } +class ConfigOutput { + final String name; + late double scale; + late bool pwm; + ConfigOutput.parse(this.name, Map json) { + scale = json['scale']?? 1; + pwm = json['pwm']??false; + } +} + //TODO Decide regarding null values or not! class ConfigFile { ConfigPrinter? configPrinter; ConfigHeaterBed? configHeaterBed; Map extruders = HashMap(); + Map outputs = HashMap(); ConfigFile(); @@ -80,6 +91,13 @@ class ConfigFile { } extruders[key] = ConfigExtruder.parse(key, jsonChild); } + + if (key.startsWith('output')) { + List split = key.split(" "); + String name = split.length > 1 ? split.skip(1).join(" ") : split[0]; + Map jsonChild = Map.of(rawConfig[key]); + outputs[name] = ConfigOutput.parse(name, jsonChild); + } }); //ToDo parse the config for e.g. EXTRUDERS (Temp settings), ... diff --git a/lib/dto/machine/Printer.dart b/lib/dto/machine/Printer.dart index f1e7d0e2..ed705a35 100644 --- a/lib/dto/machine/Printer.dart +++ b/lib/dto/machine/Printer.dart @@ -458,6 +458,7 @@ class TemperatureSensor { class OutputPin { String name; + // This value is between 0-1 double value = 0.0; OutputPin(this.name); diff --git a/lib/service/PrinterService.dart b/lib/service/PrinterService.dart index f568b90f..43881718 100644 --- a/lib/service/PrinterService.dart +++ b/lib/service/PrinterService.dart @@ -476,9 +476,9 @@ class PrinterService { }); } - outputPin(String pinName, double perc) { + outputPin(String pinName, double value) { _webSocket.sendObject("printer.gcode.script", null, - params: {'script': "SET_PIN PIN=$pinName VALUE=${perc.toInt()}"}); + params: {'script': "SET_PIN PIN=$pinName VALUE=${value.toStringAsFixed(2)}"}); } gCodeMacro(String macro) { diff --git a/lib/ui/dialog/editForm/editForm_view.dart b/lib/ui/dialog/editForm/editForm_view.dart index 2b9fb02a..9e73b333 100644 --- a/lib/ui/dialog/editForm/editForm_view.dart +++ b/lib/ui/dialog/editForm/editForm_view.dart @@ -9,8 +9,9 @@ class EditFormDialogViewArguments { final num? min; final num? max; final num? current; + final int? fraction; - EditFormDialogViewArguments({this.min, this.max, this.current}); + EditFormDialogViewArguments({this.min, this.max, this.current, this.fraction}); } class EditFormDialogView extends StatelessWidget { @@ -70,7 +71,8 @@ class NumField extends ViewModelWidget { EditFormDialogViewArguments passedData = request.data; num currentValue = passedData.current ?? 0; num lowerBorder = passedData.min ?? 0; - num upperBorder = passedData.max ?? 300; //ToDo set to printers Max temp + num upperBorder = passedData.max ?? 100; + int frac = passedData.fraction ?? 0; return FormBuilderTextField( autofocus: true, @@ -81,7 +83,7 @@ class NumField extends ViewModelWidget { FormBuilderValidators.required(context) ]), valueTransformer: (String? text) => text == null ? 0 : num.tryParse(text), - initialValue: currentValue.toStringAsFixed(0), + initialValue: currentValue.toStringAsFixed(frac.toInt()), name: 'newValue', style: Theme.of(context).inputDecorationTheme.counterStyle, keyboardType: diff --git a/lib/ui/views/overview/tabs/control_tab.dart b/lib/ui/views/overview/tabs/control_tab.dart index aaeadd04..0c1cee9b 100644 --- a/lib/ui/views/overview/tabs/control_tab.dart +++ b/lib/ui/views/overview/tabs/control_tab.dart @@ -370,11 +370,12 @@ class PinsCard extends ViewModelWidget { List rows = []; for (var pin in model.printer.outputPins) { + var configForOutput = model.configForOutput(pin.name); var row = _PinTile( name: model.beautifyName(pin.name), - value: pin.value, + value: pin.value * (configForOutput?.scale ?? 1), width: width, - onTap: () => model.onEditPin(pin), + onTap: () => model.onEditPin(pin, configForOutput), ); rows.add(row); } @@ -384,6 +385,8 @@ class PinsCard extends ViewModelWidget { class _PinTile extends StatelessWidget { final String name; + + /// Expect a value between 0-Scale! final double value; final double width; final VoidCallback? onTap; @@ -397,8 +400,9 @@ class _PinTile extends StatelessWidget { }) : super(key: key); String get pinValue { - double perc = value * 100; - if (value > 0) return '${perc.toStringAsFixed(0)} %'; + // double perc = value * 100; + if (value == value.round()) return value.toStringAsFixed(0); + if (value > 0) return value.toStringAsFixed(2); return 'Off'; } diff --git a/lib/ui/views/overview/tabs/control_tab_viewmodel.dart b/lib/ui/views/overview/tabs/control_tab_viewmodel.dart index c0f7446e..180c0131 100644 --- a/lib/ui/views/overview/tabs/control_tab_viewmodel.dart +++ b/lib/ui/views/overview/tabs/control_tab_viewmodel.dart @@ -1,4 +1,5 @@ import 'package:mobileraker/app/AppSetup.locator.dart'; +import 'package:mobileraker/dto/config/ConfigFile.dart'; import 'package:mobileraker/dto/machine/Printer.dart'; import 'package:mobileraker/dto/machine/PrinterSetting.dart'; import 'package:mobileraker/dto/server/Klipper.dart'; @@ -74,19 +75,26 @@ class ControlTabViewModel extends MultipleStreamViewModel { bool get hasPrinter => dataReady(_PrinterStreamKey); - onEditPin(OutputPin pin) { + ConfigOutput? configForOutput(String name) { + return printer.configFile.outputs[name]; + } + + onEditPin(OutputPin pin, ConfigOutput? configOutput) { + int fractionToShow = (configOutput == null || !configOutput.pwm) ? 0 : 2; _dialogService .showCustomDialog( variant: DialogType.editForm, - title: "Edit ${pin.name} %", + title: "Edit ${beautifyName(pin.name)} value!", mainButtonTitle: "Confirm", secondaryButtonTitle: "Cancel", data: EditFormDialogViewArguments( - max: 100, current: pin.value * 100.round())) + max: configOutput?.scale.toInt() ?? 1, + current: pin.value * (configOutput?.scale ?? 1), + fraction: fractionToShow)) .then((value) { if (value != null && value.confirmed && value.data != null) { num v = value.data; - _printerService?.outputPin(pin.name, v.toDouble() / 10); + _printerService?.outputPin(pin.name, v.toDouble()); } }); } diff --git a/pubspec.yaml b/pubspec.yaml index b8175abc..fe3dcf3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 +version: 1.1.0+2 environment: sdk: ">=2.12.0 <3.0.0"