Chronos Plugins 5.4.0
This documentation covers the plugin interfaces definitions and an example implementation.
Loading...
Searching...
No Matches
MockUseDeviceTasks.cs File Reference

Go to the source code of this file.

Classes

class  MockPlugin.Tasks.CoffeeMachineBaseTask
 Base class for our example, just contains some empty default implementations and a check for the right device type. More...
 
class  MockPlugin.Tasks.CoffeeCategory
 Custom category in the method editor for coffee making related tasks. More...
 
class  MockPlugin.Tasks.BrewCoffee
 Calls a method of the device class with one if its task parameters. More...
 
class  MockPlugin.Tasks.BrewFrappuccino
 A task working on a complex parameter set. More...
 
class  MockPlugin.Tasks.BrewFrappuccino.CompositionData
 Let's pretend the composition is really complex and better done with a custom editor. More...
 
class  MockPlugin.Tasks.BrewFrappuccino.CompositionEditor
 Provide an editor for our complex parameter set, the standard component model way. More...
 
class  MockPlugin.Tasks.PretendCoffeeMachineIsBroken
 This task will trigger a timer in our device which will make it complain about an error situation, even if at that time no task is trying to use it. More...
 
class  MockPlugin.Tasks.CoffeeMachineDoesNotWorkProperly
 In contrast to PretendCoffeeMachineIsBroken, this simulates an error that an autosampler could have while it is used by a task. More...
 

Namespaces

namespace  MockPlugin
 An example Chronos plugin. This plugin demonstrates how to write plugins for Chronos. It should give you a rough idea how different things can be done, and which interfaces are needed to provide funtionality.
 
namespace  MockPlugin.Tasks
 Example task implementations. Since there are lots of things that can be done from a task, the demo was split into many different examples each showing only few facets of what's possible. If you still think this is confusing, please let us know where we could simplify these examples.
 

Variables

evicetype
 

Variable Documentation

◆ evicetype

$ evicetype

Definition at line 48 of file MockUseDeviceTasks.cs.

49{
50 CheckForCoffeeMachine(yourDevice);
51 }
52
53 public virtual void PreValidate()
54 {
55 }
56
57 public virtual void PostValidate()
58 {
59 }
60
61 public abstract void Execute();
62 public abstract string GetTaskAction();
63
64 public IConsumableManipulator Consumables { get; set; }
65 }
66
70 public class CoffeeCategory : CustomTaskCategoryAttribute
71 {
72 public CoffeeCategory(int ranking) : base(ranking)
73 {
74 }
75
79 public override string Name => LocalizeMockPlugin.CoffeeCategory_Name_Coffee;
80 }
81
89 [CoffeeCategory(1)]
90 [ScheduleDiagramColor("Sienna")]
91 public class BrewCoffee : CoffeeMachineBaseTask, ITaskForDevice
92 {
96 public override void Execute()
97 {
98 mDevice.ShowTheMessage(Message);
99 RegisterCoffeeConsumption();
100 }
101
102 public override void PostValidate()
103 {
104 RegisterCoffeeConsumption();
105 }
106
110 private void RegisterCoffeeConsumption()
111 {
112 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice, MockConsumablesForCoffeeMakerDevice.Coffee.Name), new Quantity(-7, Units.Gram));
113 }
114
119 public override string GetTaskAction()
120 {
121 return LocalizeMockPlugin.BrewCoffee_GetTaskAction_Send_a_message_to_my_device;
122 }
123
127 public string Message { get; set; } = LocalizeMockPlugin.BrewCoffee_mMessage_Do_you_want_sugar_;
128 }
129
139 [CoffeeCategory(2)]
140 public class BrewFrappuccino : CoffeeMachineBaseTask, ITaskForDevice, IWantEditorUpdates, IGiveARuntimeHint , INotifyPropertyChanged
141 {
145 [TypeConverter(typeof(CreamTypeConverter))]
146 public enum CreamType
147 {
148 Normal,
149 LowFat,
150 Vegan
151 }
152
156 [Editor(typeof(CompositionEditor), typeof(UITypeEditor))]
157 public class CompositionData
158 {
159 [XmlIgnore]
160 public MockDevice DevInEditor { get; set; }
161
162 public CreamType Cream
163 {
164 get;
165 set;
166 }
167
168 public bool MuchIce { get; set; }
169
170 public bool DeCaffeinated { get; set; }
171
172 public uint Volume { get; set; }
173
177 public CompositionData()
178 {
179 Cream = CreamType.LowFat;
180 MuchIce = false;
181 DeCaffeinated = false;
182 Volume = 250;
183 }
184
189 public override string ToString()
190 {
191 return String.Format(LocalizeMockPlugin.CompositionData_ToString_Cream___0___MuchIce___1___Decaffeinated___2___Size___3__mL,
192 Cream, MuchIce, DeCaffeinated, Volume);
193 }
194 }
195
196 #region Component model UI type editor
197
201 public class CompositionEditor : UITypeEditor
202 {
208 public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
209 {
210 // we want a real dialog, not just a drop down box
211 return UITypeEditorEditStyle.Modal;
212 }
213
221 public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
222 {
223 var editProvider = (IWindowsFormsEditorService)provider?.GetService(typeof(IWindowsFormsEditorService));
224 // create the editor form
225 var compData = (CompositionData)value;
226 // we could get a reference to the task here: var theTask = context.Instance as BrewFrappuccino;
227 using (var myEditor = new FrappuccinoCompositionEditor(compData))
228 {
229 // our editor will only modify the parameters if it has been closed by clicking OK
230 editProvider?.ShowDialog(myEditor);
231 }
232 return value;
233 }
234 }
235
236 #endregion Component model UI type editor
237
238 private CompositionData mComposition;
239
244 public CompositionData Composition
245 {
246 get
247 {
248 if (mComposition != null && mComposition.DevInEditor == null)
249 {
250 mComposition.DevInEditor = mDevInEditor;
251 }
252 return mComposition;
253 }
254 set
255 {
256 mComposition = value;
257 if (mComposition != null)
258 {
259 mComposition.DevInEditor = mDevInEditor;
260 }
261 RaiseVolumeChanged();
262 }
263 }
264
265 public override string GetTaskAction()
266 {
267 return LocalizeMockPlugin.BrewFrappuccino_GetTaskAction_Brew_a_frappuccino__composition__ + Composition;
268 }
269
270
271 [DefaultUnit(Units.MilliLiter)]
272 public uint Volume
273 {
274 get => mComposition.Volume;
275 set
276 {
277 if(mComposition.Volume == value) return;
278 mComposition.Volume = value;
279 RaiseVolumeChanged();
280 }
281 }
282 internal void RaiseVolumeChanged()
283 {
284 PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(Volume)));
285 }
286 [DefaultUnit("mL")]
287 public uint CupSize
288 {
289 get;
290 set;
291 }
292
293 public BrewFrappuccino()
294 {
295 Composition = new CompositionData();
296 CupSize = 250;
297 }
298
302 public override void Execute()
303 {
304 mDevice.BrewFrappuccino(Composition);
305 RegisterConsumption(Composition);
306 }
307
308 public override void PostValidate()
309 {
310 RegisterConsumption(Composition);
311 }
312
317 private void RegisterConsumption(CompositionData composition)
318 {
319 var sizeFactor = composition.Volume / 125.0;
320 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice,MockConsumablesForCoffeeMakerDevice.Coffee.Name),new Quantity(-7*sizeFactor, Units.Gram));
321 string creamName;
322 switch (composition.Cream)
323 {
324 case CreamType.LowFat:
325 // intentionally picked name of a component that is not tracked. Results just in a log entry, not visible on tracker's page.
326 creamName = "Low Fat Milk";
327 break;
328 case CreamType.Normal:
329 creamName = MockConsumablesForCoffeeMakerDevice.Milk.Name;
330 break;
331 case CreamType.Vegan:
332 creamName = MockConsumablesForCoffeeMakerDevice.VeganCream.Name;
333 break;
334 default:
335 creamName = "";
336 break;
337 }
338 Consumables.ModifyLevel(CoffeeConsumableManager.GetLocationIdentifier(mDevice, creamName),new Quantity(-10*sizeFactor,Units.MilliLiter));
339 }
340
351 public void PropertyEdited(string propName, object propValue)
352 {
353 if (propName == nameof(Volume))
354 {
355 // the uint32 converter can't convert from uint32 to uint32 but throws an exception.
356 if (propValue is uint u)
357 {
358 Volume = u;
359 }
360 else
361 {
362 var conv = TypeDescriptor.GetConverter(Volume, true);
363 if (conv.IsValid(propValue))
364 {
365 // ReSharper disable once PossibleNullReferenceException
366 Volume = (uint)conv.ConvertFrom(null, System.Globalization.CultureInfo.InvariantCulture, propValue);
367 }
368 }
369 }
370 else if (propName == "Autosampler")
371 {
372 mDevInEditor = MockDevice.Instances.FirstOrDefault(someDev => someDev.Name == propValue?.ToString());
373 if (mComposition != null)
374 {
375 mComposition.DevInEditor = mDevInEditor;
376 }
377 }
378 }
379
380 private MockDevice mDevInEditor;
381
382 public event PropertyChangedEventHandler PropertyChanged;
383
384 #region Implementation of IGiveARuntimeHint
385
389 public int? CalculatedRuntime
390 {
391 get
392 {
393 if (Volume > 250)
394 {
395 return 30;
396 }
397
398 if (Volume > 100)
399 {
400 return 15;
401 }
402
403 return 10;
404 }
405 }
406
407 #endregion
408 }
409
413 [CoffeeCategory(3)]
414 // ReSharper disable once UnusedType.Global
415 public class PretendCoffeeMachineIsBroken : CoffeeMachineBaseTask, ITaskForDevice
416 {
417 public bool SoftStop { get; set; }
418 public override void Execute()
419 {
420 mDevice.TriggerAbort(LocalizeMockPlugin
421 .PretendCoffeeMachineIsBroken_Execute_The_coffee_machine_s_heater_failed_,SoftStop);
422 }
423
424 public override string GetTaskAction()
425 {
426 return String.Format(LocalizeMockPlugin.PretendCoffeeMachineIsBroken_GetTaskAction_Will_make_the_device_abort_the_schedule_after_a_few_seconds_,SoftStop);
427 }
428 }
432 [CoffeeCategory(4)]
433 public class CoffeeMachineDoesNotWorkProperly : CoffeeMachineBaseTask, ITaskForDevice
434 {
435 public string ErrorDescription { get; set; } = "Some random error message that is shown to the user";
436 public ErrorType ErrorType { get; set; } = ErrorType.MissingVial;
440 public bool ResolvedAfterHandling { get; set; } = false;
441 public override void Execute()
442 {
443 mDevice.RaiseError(ErrorDescription,ErrorType, ResolvedAfterHandling);
444 }
445
446 public override string GetTaskAction()
447 {
448 return $"Raising error type {ErrorType} with description \"{ErrorDescription}\"";
449 }
450 }
451}
ErrorType
Lets a device implementing IHaveInteractiveErrorHandling specify which kind of error occurred.
Helps you manipulate the desired consumable, or works as a dummy.
void Execute()
Do whatever you have to do with your parameters.
void PostValidate()
Called after the schedule construction is completed.
string GetTaskAction()
Description of the tasks's action (for hints/time table)
To be implemented if the task needs to access a device ("Autosampler" property in Chronos)
If you can calculate your runtime, you should implement this interface.
Implement this interface in your task if you want the method editor to notify it of changed propertie...
void PropertyEdited(string propName, object propValue)
This will be called as soon as a property was changed in the method editor.
Use this if none of the predefined categories fit and you have a better idea than "Misc".
Keeps track of all consumables that are associated to our mock coffee machine.
static string GetLocationIdentifier(MockDevice dev, string ingredientName)
A chronos plugin implementation for a fake device. We pretend we are controlling a mixture of coffee ...
Definition: MockDevice.cs:53
Just provide a TypeConverter, and Chronos is happy.