[{"data":1,"prerenderedAt":3024},["ShallowReactive",2],{"navigation":3,"\u002Fconnector-development\u002Ftutorial\u002Fbuild-a-sila-client":1025,"\u002Fconnector-development\u002Ftutorial\u002Fbuild-a-sila-client-surround":3019},[4,59,188,271,449,613,806,846,1008],{"title":5,"type":6,"device":6,"path":7,"stem":8,"children":9,"page":41},"Get Started",null,"\u002Fget-started\u002F","01.get-started",[10,15,42,47,51,55],{"title":11,"path":12,"stem":13,"type":14,"device":6},"Welcome to UniteLabs","\u002Fget-started\u002Fwelcome\u002F","01.get-started\u002F00.welcome","landing",{"title":16,"type":6,"device":6,"path":17,"stem":18,"children":19,"page":41},"Setup","\u002Fget-started\u002Fsetup\u002F","01.get-started\u002F01.setup",[20,25,29,33,37],{"title":21,"path":22,"stem":23,"type":24,"device":6},"Get access","\u002Fget-started\u002Fsetup\u002Fget-access\u002F","01.get-started\u002F01.setup\u002F00.get-access","howto",{"title":26,"path":27,"stem":28,"type":24,"device":6},"GroundControl","\u002Fget-started\u002Fsetup\u002Fgroundcontrol\u002F","01.get-started\u002F01.setup\u002F10.groundcontrol",{"title":30,"path":31,"stem":32,"type":24,"device":6},"Connect to Platform","\u002Fget-started\u002Fsetup\u002Fconnect-to-platform\u002F","01.get-started\u002F01.setup\u002F20.connect-to-platform",{"title":34,"path":35,"stem":36,"type":24,"device":6},"Set up your development machine","\u002Fget-started\u002Fsetup\u002Fdeveloper-machine\u002F","01.get-started\u002F01.setup\u002F30.developer-machine",{"title":38,"path":39,"stem":40,"type":24,"device":6},"SDK installation","\u002Fget-started\u002Fsetup\u002Fsdk-installation\u002F","01.get-started\u002F01.setup\u002F40.sdk-installation",false,{"title":43,"path":44,"stem":45,"type":46,"device":6},"Control a device","\u002Fget-started\u002Fcontrol-a-device\u002F","01.get-started\u002F02.control-a-device","tutorial",{"title":48,"path":49,"stem":50,"type":46,"device":6},"Liquid handling as code","\u002Fget-started\u002Fliquid-handling-as-code\u002F","01.get-started\u002F03.liquid-handling-as-code",{"title":52,"path":53,"stem":54,"type":46,"device":6},"Automate your workflows","\u002Fget-started\u002Fautomate-your-workflows\u002F","01.get-started\u002F04.automate-your-workflows",{"title":56,"path":57,"stem":58,"type":6,"device":6},"Self-Paced Setup Guide","\u002Fget-started\u002Fself-onboarding\u002F","01.get-started\u002F90.self-onboarding",{"title":60,"type":6,"device":6,"path":61,"stem":62,"children":63,"page":41},"How-to","\u002Fhow-to\u002F","02.how-to",[64,118,163,180],{"title":65,"type":6,"device":6,"path":66,"stem":67,"children":68,"page":41},"Connectors and devices","\u002Fhow-to\u002Fintegrate\u002F","02.how-to\u002F02.integrate",[69,102],{"title":70,"type":6,"device":6,"path":71,"stem":72,"children":73,"page":41},"Connect a device","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device",[74,78,82,86,90,94,98],{"title":75,"path":76,"stem":77,"type":24,"device":6},"Connector Configuration","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fconnector-configuration\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F10.connector-configuration",{"title":79,"path":80,"stem":81,"type":24,"device":6},"With an executable","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fwith-an-executable\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F20.with-an-executable",{"title":83,"path":84,"stem":85,"type":24,"device":6},"From source","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Ffrom-source\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F30.from-source",{"title":87,"path":88,"stem":89,"type":24,"device":6},"Build your own","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fbuild-yourself\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F40.build-yourself",{"title":91,"path":92,"stem":93,"type":24,"device":6},"Headless install","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fheadless-install\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F50.headless-install",{"title":95,"path":96,"stem":97,"type":24,"device":6},"Raspberry Pi","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fraspberry-pi\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F55.raspberry-pi",{"title":99,"path":100,"stem":101,"type":24,"device":6},"Multi-device Networking","\u002Fhow-to\u002Fintegrate\u002Fconnect-a-device\u002Fmultiple-devices\u002F","02.how-to\u002F02.integrate\u002F20.connect-a-device\u002F60.multiple-devices",{"title":103,"type":6,"device":6,"path":104,"stem":105,"children":106,"page":41},"Use a device","\u002Fhow-to\u002Fintegrate\u002Fuse-a-device\u002F","02.how-to\u002F02.integrate\u002F30.use-a-device",[107,110,114],{"title":26,"path":108,"stem":109,"type":24,"device":6},"\u002Fhow-to\u002Fintegrate\u002Fuse-a-device\u002Fgroundcontrol\u002F","02.how-to\u002F02.integrate\u002F30.use-a-device\u002F10.groundcontrol",{"title":111,"path":112,"stem":113,"type":24,"device":6},"Platform","\u002Fhow-to\u002Fintegrate\u002Fuse-a-device\u002Fplatform\u002F","02.how-to\u002F02.integrate\u002F30.use-a-device\u002F20.platform",{"title":115,"path":116,"stem":117,"type":24,"device":6},"UniteLabs SDK & REST API","\u002Fhow-to\u002Fintegrate\u002Fuse-a-device\u002Fpython\u002F","02.how-to\u002F02.integrate\u002F30.use-a-device\u002F30.python",{"title":119,"type":6,"device":6,"path":120,"stem":121,"children":122,"page":41},"Workflows","\u002Fhow-to\u002Fautomate\u002F","02.how-to\u002F07.automate",[123,127,131,135,139,143,147,151,155,159],{"title":124,"path":125,"stem":126,"type":24,"device":6},"Deploy a workflow","\u002Fhow-to\u002Fautomate\u002Fdeploy-a-workflow\u002F","02.how-to\u002F07.automate\u002F30.deploy-a-workflow",{"title":128,"path":129,"stem":130,"type":24,"device":6},"Run a workflow","\u002Fhow-to\u002Fautomate\u002Frun-a-workflow\u002F","02.how-to\u002F07.automate\u002F35.run-a-workflow",{"title":132,"path":133,"stem":134,"type":24,"device":6},"CI\u002FCD for workflows","\u002Fhow-to\u002Fautomate\u002Fcicd-for-workflows\u002F","02.how-to\u002F07.automate\u002F40.cicd-for-workflows",{"title":136,"path":137,"stem":138,"type":24,"device":6},"HITL basics","\u002Fhow-to\u002Fautomate\u002Fbasic-hitl\u002F","02.how-to\u002F07.automate\u002F50.basic-hitl",{"title":140,"path":141,"stem":142,"type":24,"device":6},"Slack notifications and operator confirmation","\u002Fhow-to\u002Fautomate\u002Fslack-notifications\u002F","02.how-to\u002F07.automate\u002F52.slack-notifications",{"title":144,"path":145,"stem":146,"type":24,"device":6},"Typed operator inputs","\u002Fhow-to\u002Fautomate\u002Ftyped-operator-inputs\u002F","02.how-to\u002F07.automate\u002F55.typed-operator-inputs",{"title":148,"path":149,"stem":150,"type":24,"device":6},"Pause and resume a run","\u002Fhow-to\u002Fautomate\u002Fpause-and-resume\u002F","02.how-to\u002F07.automate\u002F57.pause-and-resume",{"title":152,"path":153,"stem":154,"type":24,"device":6},"Error recovery","\u002Fhow-to\u002Fautomate\u002Fbasic-error-handling\u002F","02.how-to\u002F07.automate\u002F60.basic-error-handling",{"title":156,"path":157,"stem":158,"type":24,"device":6},"Advanced error handling","\u002Fhow-to\u002Fautomate\u002Fadvanced-error-handling\u002F","02.how-to\u002F07.automate\u002F70.advanced-error-handling",{"title":160,"path":161,"stem":162,"type":24,"device":6},"Emit lineage events","\u002Fhow-to\u002Fautomate\u002Femitting-lineage-events\u002F","02.how-to\u002F07.automate\u002F90.emitting-lineage-events",{"title":164,"type":6,"device":6,"path":165,"stem":166,"children":167,"page":41},"Data","\u002Fhow-to\u002Fobserve\u002F","02.how-to\u002F08.observe",[168,172,176],{"title":169,"path":170,"stem":171,"type":24,"device":6},"File System Connector","\u002Fhow-to\u002Fobserve\u002Ffilesystem-connector\u002F","02.how-to\u002F08.observe\u002F10.filesystem-connector",{"title":173,"path":174,"stem":175,"type":24,"device":6},"Building an ETL","\u002Fhow-to\u002Fobserve\u002Fbuilding-an-etl\u002F","02.how-to\u002F08.observe\u002F20.building-an-etl",{"title":177,"path":178,"stem":179,"type":24,"device":6},"Read lineage events","\u002Fhow-to\u002Fobserve\u002Freading-lineage-events\u002F","02.how-to\u002F08.observe\u002F30.reading-lineage-events",{"title":111,"type":6,"device":6,"path":181,"stem":182,"children":183,"page":41},"\u002Fhow-to\u002Fplatform\u002F","02.how-to\u002F09.platform",[184],{"title":185,"path":186,"stem":187,"type":24,"device":6},"UniteLabs Desktop","\u002Fhow-to\u002Fplatform\u002Funitelabs-desktop\u002F","02.how-to\u002F09.platform\u002F10.unitelabs-desktop",{"title":189,"type":6,"device":6,"path":190,"stem":191,"children":192},"Technical Reference","\u002Ftechnical-reference\u002F","03.technical-reference",[193,196,201,213,226,235,244,253,262],{"title":194,"path":190,"stem":195,"type":14,"device":6},"Overview","03.technical-reference\u002Findex",{"title":197,"path":198,"stem":199,"type":200,"device":6},"REST API","\u002Ftechnical-reference\u002Frest-api\u002F","03.technical-reference\u002F01.rest-api","reference",{"title":119,"type":6,"device":6,"path":202,"stem":203,"children":204,"page":41},"\u002Ftechnical-reference\u002Fautomate\u002F","03.technical-reference\u002F07.automate",[205,209],{"title":206,"path":207,"stem":208,"type":200,"device":6},"Workflow template","\u002Ftechnical-reference\u002Fautomate\u002Fworkflow-template\u002F","03.technical-reference\u002F07.automate\u002F05.workflow-template",{"title":210,"path":211,"stem":212,"type":200,"device":6},"Workflows REST API","\u002Ftechnical-reference\u002Fautomate\u002Fworkflows-api\u002F","03.technical-reference\u002F07.automate\u002F80.workflows-api",{"title":26,"type":6,"device":6,"path":214,"stem":215,"children":216},"\u002Ftechnical-reference\u002Fgroundcontrol\u002F","03.technical-reference\u002F10.groundcontrol\u002Findex",[217,218,222],{"title":194,"path":214,"stem":215,"type":14,"device":6},{"title":219,"path":220,"stem":221,"type":200,"device":6},"Network requirements","\u002Ftechnical-reference\u002Fgroundcontrol\u002Fnetwork-requirements\u002F","03.technical-reference\u002F10.groundcontrol\u002F10.network-requirements",{"title":223,"path":224,"stem":225,"type":200,"device":6},"Changelog","\u002Ftechnical-reference\u002Fgroundcontrol\u002Fchangelog\u002F","03.technical-reference\u002F10.groundcontrol\u002F20.changelog",{"title":227,"type":6,"device":6,"path":228,"stem":229,"children":230},"UniteLabs SDK","\u002Ftechnical-reference\u002Fpython-sdk\u002F","03.technical-reference\u002F20.python-sdk\u002Findex",[231,232],{"title":194,"path":228,"stem":229,"type":14,"device":6},{"title":223,"path":233,"stem":234,"type":200,"device":6},"\u002Ftechnical-reference\u002Fpython-sdk\u002Fchangelog\u002F","03.technical-reference\u002F20.python-sdk\u002F20.changelog",{"title":236,"type":6,"device":6,"path":237,"stem":238,"children":239},"Liquid Handling SDK","\u002Ftechnical-reference\u002Fpython-liquid-handling-sdk\u002F","03.technical-reference\u002F30.python-liquid-handling-sdk\u002Findex",[240,241],{"title":194,"path":237,"stem":238,"type":14,"device":6},{"title":223,"path":242,"stem":243,"type":200,"device":6},"\u002Ftechnical-reference\u002Fpython-liquid-handling-sdk\u002Fchangelog\u002F","03.technical-reference\u002F30.python-liquid-handling-sdk\u002F20.changelog",{"title":245,"type":6,"device":6,"path":246,"stem":247,"children":248},"Labware","\u002Ftechnical-reference\u002Flabware\u002F","03.technical-reference\u002F40.labware\u002Findex",[249,250],{"title":194,"path":246,"stem":247,"type":14,"device":6},{"title":223,"path":251,"stem":252,"type":200,"device":6},"\u002Ftechnical-reference\u002Flabware\u002Fchangelog\u002F","03.technical-reference\u002F40.labware\u002F20.changelog",{"title":254,"type":6,"device":6,"path":255,"stem":256,"children":257},"Python Omnibus","\u002Ftechnical-reference\u002Fpython-omnibus\u002F","03.technical-reference\u002F50.python-omnibus\u002Findex",[258,259],{"title":194,"path":255,"stem":256,"type":14,"device":6},{"title":223,"path":260,"stem":261,"type":200,"device":6},"\u002Ftechnical-reference\u002Fpython-omnibus\u002Fchangelog\u002F","03.technical-reference\u002F50.python-omnibus\u002F20.changelog",{"title":263,"type":6,"device":6,"path":264,"stem":265,"children":266},"Python CDK","\u002Ftechnical-reference\u002Fpython-cdk\u002F","03.technical-reference\u002F60.python-cdk\u002Findex",[267,268],{"title":194,"path":264,"stem":265,"type":14,"device":6},{"title":223,"path":269,"stem":270,"type":200,"device":6},"\u002Ftechnical-reference\u002Fpython-cdk\u002Fchangelog\u002F","03.technical-reference\u002F60.python-cdk\u002F20.changelog",{"title":272,"type":6,"device":6,"path":273,"stem":274,"children":275,"page":41},"Concepts","\u002Fconcepts\u002F","04.concepts",[276,315,339,387,426],{"title":277,"type":6,"device":6,"path":278,"stem":279,"children":280,"page":41},"Labs as code","\u002Fconcepts\u002Flabs-as-code\u002F","04.concepts\u002F01.labs-as-code",[281,286,290],{"title":282,"path":283,"stem":284,"type":285,"device":6},"Lab as Code","\u002Fconcepts\u002Flabs-as-code\u002Fwhy-code\u002F","04.concepts\u002F01.labs-as-code\u002F00.why-code","explanation",{"title":287,"path":288,"stem":289,"type":285,"device":6},"How it works","\u002Fconcepts\u002Flabs-as-code\u002Fhow-it-works\u002F","04.concepts\u002F01.labs-as-code\u002F01.how-it-works",{"title":291,"type":6,"device":6,"path":292,"stem":293,"children":294,"page":41},"Use Cases","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases",[295,299,303,307,311],{"title":296,"path":297,"stem":298,"type":285,"device":6},"Instrument Control","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002Flow-level-instrument-control\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases\u002F10.low-level-instrument-control",{"title":300,"path":301,"stem":302,"type":285,"device":6},"Multi-device Control","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002Fmulti-device-control\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases\u002F20.multi-device-control",{"title":304,"path":305,"stem":306,"type":285,"device":6},"Workflow Orchestration","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002Fworkflow-orchestration\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases\u002F30.workflow-orchestration",{"title":308,"path":309,"stem":310,"type":285,"device":6},"Custom Apps and LIMS Integration","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002Fcustom-apps-lims\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases\u002F40.custom-apps-lims",{"title":312,"path":313,"stem":314,"type":285,"device":6},"Scale and Fleet Management","\u002Fconcepts\u002Flabs-as-code\u002Fuse-cases\u002Fscale-and-fleet\u002F","04.concepts\u002F01.labs-as-code\u002F02.use-cases\u002F50.scale-and-fleet",{"title":65,"type":6,"device":6,"path":316,"stem":317,"children":318,"page":41},"\u002Fconcepts\u002Fintegrate\u002F","04.concepts\u002F02.integrate",[319,323,327,331,335],{"title":320,"path":321,"stem":322,"type":285,"device":6},"Device","\u002Fconcepts\u002Fintegrate\u002Fdevice\u002F","04.concepts\u002F02.integrate\u002F05.device",{"title":324,"path":325,"stem":326,"type":285,"device":6},"Connector","\u002Fconcepts\u002Fintegrate\u002Fconnector\u002F","04.concepts\u002F02.integrate\u002F10.connector",{"title":328,"path":329,"stem":330,"type":285,"device":6},"Module","\u002Fconcepts\u002Fintegrate\u002Fmodule\u002F","04.concepts\u002F02.integrate\u002F20.module",{"title":332,"path":333,"stem":334,"type":285,"device":6},"Action","\u002Fconcepts\u002Fintegrate\u002Faction\u002F","04.concepts\u002F02.integrate\u002F30.action",{"title":336,"path":337,"stem":338,"type":285,"device":6},"Subscription","\u002Fconcepts\u002Fintegrate\u002Fsubscription\u002F","04.concepts\u002F02.integrate\u002F40.subscription",{"title":340,"type":6,"device":6,"path":341,"stem":342,"children":343,"page":41},"Liquid handling and robots","\u002Fconcepts\u002Foperate\u002F","04.concepts\u002F03.operate",[344,348,352,356,359,363,367,371,375,379,383],{"title":345,"path":346,"stem":347,"type":285,"device":6},"Liquid Handling","\u002Fconcepts\u002Foperate\u002Fliquid-handling\u002F","04.concepts\u002F03.operate\u002F10.liquid-handling",{"title":349,"path":350,"stem":351,"type":285,"device":6},"Modules","\u002Fconcepts\u002Foperate\u002Fmodules\u002F","04.concepts\u002F03.operate\u002F20.modules",{"title":353,"path":354,"stem":355,"type":285,"device":6},"Deck","\u002Fconcepts\u002Foperate\u002Fdeck\u002F","04.concepts\u002F03.operate\u002F30.deck",{"title":245,"path":357,"stem":358,"type":285,"device":6},"\u002Fconcepts\u002Foperate\u002Flabware\u002F","04.concepts\u002F03.operate\u002F40.labware",{"title":360,"path":361,"stem":362,"type":285,"device":6},"Liquids","\u002Fconcepts\u002Foperate\u002Fliquids\u002F","04.concepts\u002F03.operate\u002F50.liquids",{"title":364,"path":365,"stem":366,"type":285,"device":6},"Liquid Classes","\u002Fconcepts\u002Foperate\u002Fliquid-classes\u002F","04.concepts\u002F03.operate\u002F60.liquid-classes",{"title":368,"path":369,"stem":370,"type":285,"device":6},"Parameter Sets","\u002Fconcepts\u002Foperate\u002Fparameter-sets\u002F","04.concepts\u002F03.operate\u002F65.parameter-sets",{"title":372,"path":373,"stem":374,"type":285,"device":6},"Tips and Tip Tracking","\u002Fconcepts\u002Foperate\u002Ftips\u002F","04.concepts\u002F03.operate\u002F70.tips",{"title":376,"path":377,"stem":378,"type":285,"device":6},"Simulation","\u002Fconcepts\u002Foperate\u002Fsimulation\u002F","04.concepts\u002F03.operate\u002F80.simulation",{"title":380,"path":381,"stem":382,"type":285,"device":6},"Error Handling","\u002Fconcepts\u002Foperate\u002Ferror-handling\u002F","04.concepts\u002F03.operate\u002F90.error-handling",{"title":384,"path":385,"stem":386,"type":285,"device":6},"Robot Arms","\u002Fconcepts\u002Foperate\u002Frobot-arms\u002F","04.concepts\u002F03.operate\u002F95.robot-arms",{"title":119,"type":6,"device":6,"path":388,"stem":389,"children":390,"page":41},"\u002Fconcepts\u002Fautomate\u002F","04.concepts\u002F07.automate",[391,395,399,403,407,411,415,419,423],{"title":392,"path":393,"stem":394,"type":285,"device":6},"Workflow","\u002Fconcepts\u002Fautomate\u002Fworkflow\u002F","04.concepts\u002F07.automate\u002F10.workflow",{"title":396,"path":397,"stem":398,"type":285,"device":6},"Phase","\u002Fconcepts\u002Fautomate\u002Fphase\u002F","04.concepts\u002F07.automate\u002F20.phase",{"title":400,"path":401,"stem":402,"type":285,"device":6},"Step","\u002Fconcepts\u002Fautomate\u002Fstep\u002F","04.concepts\u002F07.automate\u002F30.step",{"title":404,"path":405,"stem":406,"type":285,"device":6},"Runs","\u002Fconcepts\u002Fautomate\u002Fruns\u002F","04.concepts\u002F07.automate\u002F40.runs",{"title":408,"path":409,"stem":410,"type":285,"device":6},"Input","\u002Fconcepts\u002Fautomate\u002Finput\u002F","04.concepts\u002F07.automate\u002F50.input",{"title":412,"path":413,"stem":414,"type":285,"device":6},"Artifacts","\u002Fconcepts\u002Fautomate\u002Fartifacts\u002F","04.concepts\u002F07.automate\u002F60.artifacts",{"title":416,"path":417,"stem":418,"type":285,"device":6},"Logs","\u002Fconcepts\u002Fautomate\u002Flogs\u002F","04.concepts\u002F07.automate\u002F70.logs",{"title":420,"path":421,"stem":422,"type":285,"device":6},"Human in the Loop","\u002Fconcepts\u002Fautomate\u002Fhuman-in-the-loop\u002F","04.concepts\u002F07.automate\u002F80.human-in-the-loop",{"title":380,"path":424,"stem":425,"type":285,"device":6},"\u002Fconcepts\u002Fautomate\u002Ferror-handling\u002F","04.concepts\u002F07.automate\u002F90.error-handling",{"title":164,"type":6,"device":6,"path":427,"stem":428,"children":429,"page":41},"\u002Fconcepts\u002Fobserve\u002F","04.concepts\u002F08.observe",[430,433,437,441,445],{"title":194,"path":431,"stem":432,"type":14,"device":6},"\u002Fconcepts\u002Fobserve\u002Foverview\u002F","04.concepts\u002F08.observe\u002F10.overview",{"title":434,"path":435,"stem":436,"type":285,"device":6},"Object Storage","\u002Fconcepts\u002Fobserve\u002Fstorage\u002F","04.concepts\u002F08.observe\u002F10.storage",{"title":438,"path":439,"stem":440,"type":285,"device":6},"Secrets","\u002Fconcepts\u002Fobserve\u002Fsecrets\u002F","04.concepts\u002F08.observe\u002F20.secrets",{"title":442,"path":443,"stem":444,"type":285,"device":6},"Data sources","\u002Fconcepts\u002Fobserve\u002Fdata-sources\u002F","04.concepts\u002F08.observe\u002F30.data-sources",{"title":446,"path":447,"stem":448,"type":285,"device":6},"Data lineage","\u002Fconcepts\u002Fobserve\u002Fdata-lineage\u002F","04.concepts\u002F08.observe\u002F40.data-lineage",{"title":450,"type":6,"device":6,"path":451,"stem":452,"children":453,"page":41},"Devices","\u002Fdevices\u002F","05.devices",[454,457,505,518,534,571,595],{"title":194,"path":455,"stem":456,"type":14,"device":6},"\u002Fdevices\u002Foverview\u002F","05.devices\u002F00.overview",{"title":458,"path":459,"page":41,"children":460},"Heater-shakers","\u002Fdevices\u002Fheater-shakers\u002F",[461,482,492],{"title":462,"path":463,"stem":464,"type":200,"device":465},"QInstruments BioShake","\u002Fdevices\u002Fqinstruments-bioshake\u002F","05.devices\u002F10.qinstruments-bioshake",{"slug":466,"vendor":467,"category":468,"connector":466,"package":469,"models":470,"communication":477,"vendor_software":6,"os":478},"qinstruments-bioshake","QInstruments","Plate Shakers & Temperature Control","unitelabs-qinstruments-bioshake",[471,472,473,474,475,476],"BioShake 3000 \u002F 3000 elm \u002F 3000 elm DWP","BioShake 3000-T \u002F 3000-T elm","BioShake 5000 elm","BioShake D30 \u002F D30 elm \u002F D30-T \u002F D30-T elm","BioShake Q1 \u002F Q1 (1.2 mm) \u002F Q1 (3.0 mm) \u002F Q2","HeatPlate","serial (RS-232 over USB)",[479,480,481],"windows","linux","macos",{"title":483,"path":484,"stem":485,"type":200,"device":486},"QInstruments ColdPlate","\u002Fdevices\u002Fqinstruments-coldplate\u002F","05.devices\u002F20.qinstruments-coldplate",{"slug":487,"vendor":467,"category":468,"connector":466,"package":469,"models":488,"communication":477,"vendor_software":6,"os":491},"qinstruments-coldplate",[489,490],"ColdPlate","ColdPlate slim",[479,480,481],{"title":493,"path":494,"stem":495,"type":200,"device":496},"Inheco Thermoshake","\u002Fdevices\u002Finheco-thermoshake\u002F","05.devices\u002F30.inheco-thermoshake",{"slug":497,"vendor":498,"category":468,"connector":499,"models":500},"inheco-thermoshake","Inheco","inheco-tec-controller",[501,502,503,504],"Thermoshake AC","Thermoshake AC LC","Thermoshake Classic","Thermoshake RM",{"title":506,"path":507,"page":41,"children":508},"Incubation","\u002Fdevices\u002Fincubation\u002F",[509],{"title":510,"path":511,"stem":512,"type":200,"device":513},"Inheco SCILA","\u002Fdevices\u002Finheco-scila\u002F","05.devices\u002F40.inheco-scila",{"slug":514,"vendor":498,"category":506,"connector":514,"models":515},"inheco-scila",[516,517],"SCILA","SCILA MIX 2-gas mixing device",{"title":519,"path":520,"page":41,"children":521},"Thermal cyclers","\u002Fdevices\u002Fthermal-cyclers\u002F",[522],{"title":523,"path":524,"stem":525,"type":200,"device":526},"Inheco ODTC","\u002Fdevices\u002Finheco-odtc\u002F","05.devices\u002F50.inheco-odtc",{"slug":527,"vendor":498,"category":528,"connector":527,"models":529},"inheco-odtc","Thermal Cycler",[530,531,532,533],"ODTC 96","ODTC 96XL","ODTC 384","ODTC 384XL",{"title":535,"path":536,"page":41,"children":537},"Readers","\u002Fdevices\u002Freaders\u002F",[538,547,556],{"title":539,"path":540,"stem":541,"type":200,"device":542},"Agilent Biotek Gen5","\u002Fdevices\u002Fbiotek-gen5\u002F","05.devices\u002F60.biotek-gen5",{"slug":543,"vendor":544,"category":545,"connector":546},"biotek-gen5","Agilent","Readers & Imagers","gen5",{"title":548,"path":549,"stem":550,"type":200,"device":551},"Biotek Synergy H1","\u002Fdevices\u002Fbiotek-synergy-h1\u002F","05.devices\u002F70.biotek-synergy-h1",{"slug":552,"vendor":544,"category":545,"connector":553,"models":554},"biotek-synergy-h1","agilent-synergy-h1",[555],"BioTek Synergy H1",{"title":557,"path":558,"stem":559,"type":200,"device":560},"Tecan Infinite 200","\u002Fdevices\u002Ftecan-infinite-200\u002F","05.devices\u002F75.tecan-infinite-200",{"slug":561,"vendor":562,"category":545,"connector":561,"package":563,"models":564,"communication":568,"vendor_software":569,"os":570},"tecan-infinite-200","Tecan","unitelabs-tecan-infinite-200",[565,566,567],"Infinite F200","Infinite M200","Infinite M200 Pro","USB","i-control on Windows only, for its USB driver",[479,480,481],{"title":572,"path":573,"page":41,"children":574},"Tilt & turn","\u002Fdevices\u002Ftilt-and-turn\u002F",[575,585],{"title":576,"path":577,"stem":578,"type":200,"device":579},"QInstruments TiltStation","\u002Fdevices\u002Fqinstruments-tiltstation\u002F","05.devices\u002F80.qinstruments-tiltstation",{"slug":580,"vendor":467,"category":581,"connector":466,"package":469,"models":582,"communication":477,"vendor_software":6,"os":584},"qinstruments-tiltstation","Plate Tilting",[583],"TiltStation",[479,480,481],{"title":586,"path":587,"stem":588,"type":200,"device":589},"QInstruments TurnStation","\u002Fdevices\u002Fqinstruments-turnstation\u002F","05.devices\u002F90.qinstruments-turnstation",{"slug":590,"vendor":467,"category":591,"connector":466,"package":469,"models":592,"communication":477,"vendor_software":6,"os":594},"qinstruments-turnstation","Plate Rotating",[593],"TurnStation",[479,480,481],{"title":596,"path":597,"page":41,"children":598},"Robots","\u002Fdevices\u002Frobots\u002F",[599],{"title":600,"path":601,"stem":602,"type":200,"device":603},"Brooks PreciseFlex 400","\u002Fdevices\u002Fbrooks-preciseflex-400\u002F","05.devices\u002F95.brooks-preciseflex-400",{"slug":604,"vendor":605,"category":596,"connector":604,"package":606,"models":607,"communication":611,"vendor_software":6,"os":612},"brooks-preciseflex-400","Brooks Automation","unitelabs-brooks-preciseflex-400",[608,609,610],"PreciseFlex 400, standard reach, 400 \u002F 750 \u002F 1160 mm Z","PreciseFlex 400, extended reach (XR), 400 \u002F 750 \u002F 1160 mm Z","Either on a PreciseFlex linear rail (1.0, 1.5 or 2.0 m)","Ethernet (TCP)",[479,480,481],{"title":614,"type":6,"device":6,"path":615,"stem":616,"children":617,"page":41},"Liquid Handling and Robots","\u002Fliquid-handling-and-robots\u002F","06.liquid-handling-and-robots",[618,621,633,657,660,705,734,751,768,790],{"title":194,"path":619,"stem":620,"type":14,"device":6},"\u002Fliquid-handling-and-robots\u002Foverview\u002F","06.liquid-handling-and-robots\u002F00.overview",{"title":353,"type":6,"device":6,"path":622,"stem":623,"children":624,"page":41},"\u002Fliquid-handling-and-robots\u002Fdeck\u002F","06.liquid-handling-and-robots\u002F10.deck",[625,629],{"title":626,"path":627,"stem":628,"type":24,"device":6},"Building a Deck","\u002Fliquid-handling-and-robots\u002Fdeck\u002Fbuilding-a-deck\u002F","06.liquid-handling-and-robots\u002F10.deck\u002F10.building-a-deck",{"title":630,"path":631,"stem":632,"type":24,"device":6},"Save\u002FLoad a Deck","\u002Fliquid-handling-and-robots\u002Fdeck\u002Fsave-load-deck\u002F","06.liquid-handling-and-robots\u002F10.deck\u002F20.save-load-deck",{"title":634,"type":6,"device":6,"path":635,"stem":636,"children":637,"page":41},"Pipetting","\u002Fliquid-handling-and-robots\u002Fpipetting\u002F","06.liquid-handling-and-robots\u002F20.pipetting",[638,642,646,650,653],{"title":639,"path":640,"stem":641,"type":24,"device":6},"Basic Pipetting","\u002Fliquid-handling-and-robots\u002Fpipetting\u002Fbasic-pipetting\u002F","06.liquid-handling-and-robots\u002F20.pipetting\u002F10.basic-pipetting",{"title":643,"path":644,"stem":645,"type":24,"device":6},"Advanced Pipetting","\u002Fliquid-handling-and-robots\u002Fpipetting\u002Fadvanced-pipetting\u002F","06.liquid-handling-and-robots\u002F20.pipetting\u002F20.advanced-pipetting",{"title":647,"path":648,"stem":649,"type":24,"device":6},"Tip Handling","\u002Fliquid-handling-and-robots\u002Fpipetting\u002Ftip-handling\u002F","06.liquid-handling-and-robots\u002F20.pipetting\u002F30.tip-handling",{"title":364,"path":651,"stem":652,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fpipetting\u002Fliquid-classes\u002F","06.liquid-handling-and-robots\u002F20.pipetting\u002F40.liquid-classes",{"title":654,"path":655,"stem":656,"type":24,"device":6},"Labware Transport","\u002Fliquid-handling-and-robots\u002Fpipetting\u002Flabware-transport\u002F","06.liquid-handling-and-robots\u002F20.pipetting\u002F50.labware-transport",{"title":376,"path":658,"stem":659,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fsimulation\u002F","06.liquid-handling-and-robots\u002F30.simulation",{"title":661,"type":6,"device":6,"path":662,"stem":663,"children":664,"page":41},"Hamilton STAR","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star",[665,669,673,677,681,685,689,693,697,701],{"title":666,"path":667,"stem":668,"type":24,"device":6},"Positioning & Movement","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fpositioning\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F10.positioning",{"title":670,"path":671,"stem":672,"type":24,"device":6},"Gripper Module","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fcore-gripper\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F20.core-gripper",{"title":674,"path":675,"stem":676,"type":24,"device":6},"iSWAP Module","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fiswap\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F30.iswap",{"title":678,"path":679,"stem":680,"type":24,"device":6},"Using TADM","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Ftadm\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F40.tadm",{"title":682,"path":683,"stem":684,"type":24,"device":6},"Autoload Module","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fautoload\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F50.autoload",{"title":686,"path":687,"stem":688,"type":24,"device":6},"Waste Block","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fwaste-block\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F60.waste-block",{"title":690,"path":691,"stem":692,"type":24,"device":6},"Complex Mixing","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fcomplex-mixing\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F66.complex-mixing",{"title":694,"path":695,"stem":696,"type":24,"device":6},"Teaching Gripper Paddle Positions","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fgripper-positions\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F70.gripper-positions",{"title":698,"path":699,"stem":700,"type":24,"device":6},"Training a Custom Deck Position With the iSWAP","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fcustom-deck-position\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F75.custom-deck-position",{"title":702,"path":703,"stem":704,"type":200,"device":6},"Observable Commands","\u002Fliquid-handling-and-robots\u002Fhamilton-star\u002Fobservable-commands\u002F","06.liquid-handling-and-robots\u002F41.hamilton-star\u002F80.observable-commands",{"title":706,"type":6,"device":6,"path":707,"stem":708,"children":709,"page":41},"Hamilton Vantage","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage",[710,714,718,722,726,730],{"title":711,"path":712,"stem":713,"type":24,"device":6},"Waste Configuration","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fwaste-configuration\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F05.waste-configuration",{"title":715,"path":716,"stem":717,"type":24,"device":6},"Covers and Lights","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fcovers-and-lights\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F10.covers-and-lights",{"title":719,"path":720,"stem":721,"type":24,"device":6},"IDL Module","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fidl\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F20.idl",{"title":723,"path":724,"stem":725,"type":24,"device":6},"IPG Module","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fipg\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F30.ipg",{"title":727,"path":728,"stem":729,"type":24,"device":6},"XL Pipettes","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fxl-channels\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F40.xl-channels",{"title":731,"path":732,"stem":733,"type":24,"device":6},"CO-RE 96 Head","\u002Fliquid-handling-and-robots\u002Fhamilton-vantage\u002Fcore96-head\u002F","06.liquid-handling-and-robots\u002F42.hamilton-vantage\u002F50.core96-head",{"title":735,"type":6,"device":6,"path":736,"stem":737,"children":738,"page":41},"Agilent Bravo","\u002Fliquid-handling-and-robots\u002Fagilent-bravo\u002F","06.liquid-handling-and-robots\u002F43.agilent-bravo",[739,742,745,748],{"title":647,"path":740,"stem":741,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fagilent-bravo\u002Ftip-handling\u002F","06.liquid-handling-and-robots\u002F43.agilent-bravo\u002F10.tip-handling",{"title":639,"path":743,"stem":744,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fagilent-bravo\u002Fbasic-pipetting\u002F","06.liquid-handling-and-robots\u002F43.agilent-bravo\u002F20.basic-pipetting",{"title":364,"path":746,"stem":747,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fagilent-bravo\u002Fliquid-classes\u002F","06.liquid-handling-and-robots\u002F43.agilent-bravo\u002F25.liquid-classes",{"title":670,"path":749,"stem":750,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Fagilent-bravo\u002Fusing-the-gripper\u002F","06.liquid-handling-and-robots\u002F43.agilent-bravo\u002F30.using-the-gripper",{"title":752,"type":6,"device":6,"path":753,"stem":754,"children":755,"page":41},"Tecan FluentControl","\u002Fliquid-handling-and-robots\u002Ftecan-fluentcontrol\u002F","06.liquid-handling-and-robots\u002F44.tecan-fluentcontrol",[756,760,764],{"title":757,"path":758,"stem":759,"type":24,"device":6},"Connect & Run a Method","\u002Fliquid-handling-and-robots\u002Ftecan-fluentcontrol\u002Fconnect-and-run\u002F","06.liquid-handling-and-robots\u002F44.tecan-fluentcontrol\u002F10.connect-and-run",{"title":761,"path":762,"stem":763,"type":24,"device":6},"Sending XML Commands","\u002Fliquid-handling-and-robots\u002Ftecan-fluentcontrol\u002Fsending-xml-commands\u002F","06.liquid-handling-and-robots\u002F44.tecan-fluentcontrol\u002F20.sending-xml-commands",{"title":765,"path":766,"stem":767,"type":24,"device":6},"Full Workflow Example","\u002Fliquid-handling-and-robots\u002Ftecan-fluentcontrol\u002Ffull-workflow-example\u002F","06.liquid-handling-and-robots\u002F44.tecan-fluentcontrol\u002F30.full-workflow-example",{"title":769,"type":6,"device":6,"path":770,"stem":771,"children":772,"page":41},"Tecan Freedom EVO","\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo",[773,777,780,783,787],{"title":774,"path":775,"stem":776,"type":24,"device":6},"Deck & Carriers","\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002Fdeck-and-carriers\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo\u002F10.deck-and-carriers",{"title":647,"path":778,"stem":779,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002Ftip-handling\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo\u002F20.tip-handling",{"title":639,"path":781,"stem":782,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002Fbasic-pipetting\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo\u002F30.basic-pipetting",{"title":784,"path":785,"stem":786,"type":24,"device":6},"Using the Gripper (RoMa)","\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002Fusing-the-gripper\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo\u002F40.using-the-gripper",{"title":364,"path":788,"stem":789,"type":24,"device":6},"\u002Fliquid-handling-and-robots\u002Ftecan-freedom-evo\u002Fliquid-classes\u002F","06.liquid-handling-and-robots\u002F45.tecan-freedom-evo\u002F50.liquid-classes",{"title":600,"type":6,"device":6,"path":791,"stem":792,"children":793,"page":41},"\u002Fliquid-handling-and-robots\u002Fbrooks-preciseflex-400\u002F","06.liquid-handling-and-robots\u002F46.brooks-preciseflex-400",[794,798,802],{"title":795,"path":796,"stem":797,"type":24,"device":6},"Teach Positions","\u002Fliquid-handling-and-robots\u002Fbrooks-preciseflex-400\u002Fteach-positions\u002F","06.liquid-handling-and-robots\u002F46.brooks-preciseflex-400\u002F10.teach-positions",{"title":799,"path":800,"stem":801,"type":24,"device":6},"Move a Plate","\u002Fliquid-handling-and-robots\u002Fbrooks-preciseflex-400\u002Fmove-a-plate\u002F","06.liquid-handling-and-robots\u002F46.brooks-preciseflex-400\u002F20.move-a-plate",{"title":803,"path":804,"stem":805,"type":24,"device":6},"Recover from a Stop","\u002Fliquid-handling-and-robots\u002Fbrooks-preciseflex-400\u002Frecover-from-a-stop\u002F","06.liquid-handling-and-robots\u002F46.brooks-preciseflex-400\u002F30.recover-from-a-stop",{"title":245,"type":6,"device":6,"path":807,"stem":808,"children":809,"page":41},"\u002Flabware\u002F","07.labware",[810,813,817,821,825,829,833,837],{"title":194,"path":811,"stem":812,"type":14,"device":6},"\u002Flabware\u002Foverview\u002F","07.labware\u002F00.overview",{"title":814,"path":815,"stem":816,"type":200,"device":6},"Standard Labware","\u002Flabware\u002Fstandard-labware\u002F","07.labware\u002F10.standard-labware",{"title":818,"path":819,"stem":820,"type":200,"device":6},"Plates","\u002Flabware\u002Fplates\u002F","07.labware\u002F20.plates",{"title":822,"path":823,"stem":824,"type":200,"device":6},"Tips and Tip Racks","\u002Flabware\u002Ftips-and-racks\u002F","07.labware\u002F30.tips-and-racks",{"title":826,"path":827,"stem":828,"type":200,"device":6},"Tubes and Tube Racks","\u002Flabware\u002Ftubes-and-tube-racks\u002F","07.labware\u002F40.tubes-and-tube-racks",{"title":830,"path":831,"stem":832,"type":200,"device":6},"Troughs","\u002Flabware\u002Ftroughs\u002F","07.labware\u002F50.troughs",{"title":834,"path":835,"stem":836,"type":200,"device":6},"Carriers and Adapters","\u002Flabware\u002Fcarriers-and-adapters\u002F","07.labware\u002F60.carriers-and-adapters",{"title":838,"type":6,"device":6,"path":839,"stem":840,"children":841,"page":41},"Hamilton","\u002Flabware\u002Fhamilton\u002F","07.labware\u002F70.hamilton",[842],{"title":843,"path":844,"stem":845,"type":24,"device":6},"Hamilton MFX Carriers","\u002Flabware\u002Fhamilton\u002Fmfx-carriers\u002F","07.labware\u002F70.hamilton\u002F10.mfx-carriers",{"title":847,"type":6,"device":6,"path":848,"stem":849,"children":850},"Connector Development (CDK)","\u002Fconnector-development\u002F","20.connector-development",[851,853,873,906,930,986],{"title":194,"path":848,"stem":852,"type":14,"device":6},"20.connector-development\u002Findex",{"title":854,"path":855,"stem":856,"children":857,"page":41},"Getting Started","\u002Fconnector-development\u002Fgetting-started\u002F","20.connector-development\u002F10.getting-started",[858,861,865,869],{"title":194,"path":859,"stem":860,"type":285,"device":6},"\u002Fconnector-development\u002Fgetting-started\u002Foverview\u002F","20.connector-development\u002F10.getting-started\u002F10.overview",{"title":862,"path":863,"stem":864,"type":24,"device":6},"What's new","\u002Fconnector-development\u002Fgetting-started\u002Fwhats-new\u002F","20.connector-development\u002F10.getting-started\u002F20.whats-new",{"title":866,"path":867,"stem":868,"type":24,"device":6},"Installation","\u002Fconnector-development\u002Fgetting-started\u002Finstallation\u002F","20.connector-development\u002F10.getting-started\u002F30.installation",{"title":870,"path":871,"stem":872,"type":24,"device":6},"Contributing","\u002Fconnector-development\u002Fgetting-started\u002Fcontributing\u002F","20.connector-development\u002F10.getting-started\u002F40.contributing",{"title":874,"path":875,"stem":876,"children":877,"page":41},"Tutorial","\u002Fconnector-development\u002Ftutorial\u002F","20.connector-development\u002F20.tutorial",[878,882,886,890,894,898,902],{"title":879,"path":880,"stem":881,"type":46,"device":6},"Walkthrough","\u002Fconnector-development\u002Ftutorial\u002Fwalkthrough\u002F","20.connector-development\u002F20.tutorial\u002F00.walkthrough",{"title":883,"path":884,"stem":885,"type":46,"device":6},"SiLA Endpoints","\u002Fconnector-development\u002Ftutorial\u002Fsila-endpoints\u002F","20.connector-development\u002F20.tutorial\u002F15.sila-endpoints",{"title":887,"path":888,"stem":889,"type":46,"device":6},"Data Endpoints","\u002Fconnector-development\u002Ftutorial\u002Fdata-endpoints\u002F","20.connector-development\u002F20.tutorial\u002F20.data-endpoints",{"title":891,"path":892,"stem":893,"type":46,"device":6},"Controls","\u002Fconnector-development\u002Ftutorial\u002Fcontrols\u002F","20.connector-development\u002F20.tutorial\u002F30.controls",{"title":895,"path":896,"stem":897,"type":46,"device":6},"SiLA Data Types","\u002Fconnector-development\u002Ftutorial\u002Fdata-types\u002F","20.connector-development\u002F20.tutorial\u002F40.data-types",{"title":899,"path":900,"stem":901,"type":46,"device":6},"Hardware Communication","\u002Fconnector-development\u002Ftutorial\u002Fhardware-communication\u002F","20.connector-development\u002F20.tutorial\u002F90.hardware-communication",{"title":903,"path":904,"stem":905,"type":46,"device":6},"Build a SiLA client","\u002Fconnector-development\u002Ftutorial\u002Fbuild-a-sila-client\u002F","20.connector-development\u002F20.tutorial\u002F95.build-a-sila-client",{"title":272,"type":6,"device":6,"path":907,"stem":908,"children":909,"page":41},"\u002Fconnector-development\u002Fconcepts\u002F","20.connector-development\u002F30.concepts",[910,914,918,922,926],{"title":911,"path":912,"stem":913,"type":285,"device":6},"SiLA","\u002Fconnector-development\u002Fconcepts\u002Fsila\u002F","20.connector-development\u002F30.concepts\u002F00.sila",{"title":915,"path":916,"stem":917,"type":6,"device":6},"Designing Features","\u002Fconnector-development\u002Fconcepts\u002Ffeatures\u002F","20.connector-development\u002F30.concepts\u002F10.features",{"title":919,"path":920,"stem":921,"type":6,"device":6},"Designing Endpoints","\u002Fconnector-development\u002Fconcepts\u002Fsila-endpoints\u002F","20.connector-development\u002F30.concepts\u002F15.sila-endpoints",{"title":923,"path":924,"stem":925,"type":6,"device":6},"Designing Data Types","\u002Fconnector-development\u002Fconcepts\u002Fdata-types\u002F","20.connector-development\u002F30.concepts\u002F20.data-types",{"title":927,"path":928,"stem":929,"type":6,"device":6},"Connector Architecture","\u002Fconnector-development\u002Fconcepts\u002Farchitecture\u002F","20.connector-development\u002F30.concepts\u002F30.architecture",{"title":931,"path":932,"stem":933,"children":934,"page":41},"Guides","\u002Fconnector-development\u002Fguides\u002F","20.connector-development\u002F40.guides",[935,939,943,947,951,955,959,963,967,971,975,978,982],{"title":936,"path":937,"stem":938,"type":6,"device":6},"Project Structure","\u002Fconnector-development\u002Fguides\u002Fproject-structure\u002F","20.connector-development\u002F40.guides\u002F10.project-structure",{"title":940,"path":941,"stem":942,"type":24,"device":6},"Configuration","\u002Fconnector-development\u002Fguides\u002Fconfiguration\u002F","20.connector-development\u002F40.guides\u002F20.configuration",{"title":944,"path":945,"stem":946,"type":24,"device":6},"Logging","\u002Fconnector-development\u002Fguides\u002Flogging\u002F","20.connector-development\u002F40.guides\u002F21.logging",{"title":948,"path":949,"stem":950,"type":24,"device":6},"Deployment","\u002Fconnector-development\u002Fguides\u002Fdeployment\u002F","20.connector-development\u002F40.guides\u002F30.deployment",{"title":952,"path":953,"stem":954,"type":24,"device":6},"Security","\u002Fconnector-development\u002Fguides\u002Fsecurity\u002F","20.connector-development\u002F40.guides\u002F40.security",{"title":956,"path":957,"stem":958,"type":24,"device":6},"Subscriptions","\u002Fconnector-development\u002Fguides\u002Fsubscriptions\u002F","20.connector-development\u002F40.guides\u002F45.subscriptions",{"title":960,"path":961,"stem":962,"type":24,"device":6},"Execution Modes","\u002Fconnector-development\u002Fguides\u002Fexecution-modes\u002F","20.connector-development\u002F40.guides\u002F46.execution-modes",{"title":964,"path":965,"stem":966,"type":6,"device":6},"Constraints and Units","\u002Fconnector-development\u002Fguides\u002Fconstraints-and-units\u002F","20.connector-development\u002F40.guides\u002F47.constraints-and-units",{"title":968,"path":969,"stem":970,"type":6,"device":6},"Device Variants","\u002Fconnector-development\u002Fguides\u002Fdevice-variants\u002F","20.connector-development\u002F40.guides\u002F48.device-variants",{"title":972,"path":973,"stem":974,"type":6,"device":6},"Repeated Modules","\u002Fconnector-development\u002Fguides\u002Frepeated-modules\u002F","20.connector-development\u002F40.guides\u002F49.repeated-modules",{"title":380,"path":976,"stem":977,"type":24,"device":6},"\u002Fconnector-development\u002Fguides\u002Ferror-handling\u002F","20.connector-development\u002F40.guides\u002F50.error-handling",{"title":979,"path":980,"stem":981,"type":24,"device":6},"Serial Troubleshooting","\u002Fconnector-development\u002Fguides\u002Fserial-troubleshooting\u002F","20.connector-development\u002F40.guides\u002F70.serial-troubleshooting",{"title":983,"path":984,"stem":985,"type":6,"device":6},"Testing","\u002Fconnector-development\u002Fguides\u002Ftesting\u002F","20.connector-development\u002F40.guides\u002F80.testing",{"title":987,"type":6,"device":6,"path":988,"stem":989,"children":990},"References","\u002Fconnector-development\u002Freference\u002F","20.connector-development\u002F50.reference\u002Findex",[991,992,996,1000,1004],{"title":987,"path":988,"stem":989,"type":6,"device":6},{"title":993,"path":994,"stem":995,"type":6,"device":6},"Naming Conventions","\u002Fconnector-development\u002Freference\u002Fnaming-conventions\u002F","20.connector-development\u002F50.reference\u002F10.naming-conventions",{"title":997,"path":998,"stem":999,"type":6,"device":6},"Docstring Format","\u002Fconnector-development\u002Freference\u002Fdocstrings\u002F","20.connector-development\u002F50.reference\u002F20.docstrings",{"title":1001,"path":1002,"stem":1003,"type":6,"device":6},"Feature Metadata","\u002Fconnector-development\u002Freference\u002Ffeature-metadata\u002F","20.connector-development\u002F50.reference\u002F30.feature-metadata",{"title":1005,"path":1006,"stem":1007,"type":6,"device":6},"Review Checklist","\u002Fconnector-development\u002Freference\u002Freview-checklist\u002F","20.connector-development\u002F50.reference\u002F90.review-checklist",{"title":1009,"type":6,"device":6,"path":1010,"stem":1011,"children":1012},"Blog","\u002Fblog\u002F","30.blog",[1013,1016],{"title":1014,"path":1010,"stem":1015,"type":6,"device":6},"UniteLabs Blog","30.blog\u002Findex",{"title":1017,"path":1018,"stem":1019,"children":1020,"page":41},"Python","\u002Fblog\u002Fpython\u002F","30.blog\u002F01.python",[1021],{"title":1022,"path":1023,"stem":1024,"type":24,"device":6},"Python Environment and Project Management","\u002Fblog\u002Fpython\u002Fpython-environment-management\u002F","30.blog\u002F01.python\u002F10.python-environment-management",{"id":1026,"title":1027,"body":1028,"description":3012,"device":6,"extension":3013,"links":6,"meta":3014,"navigation":3015,"path":3016,"seo":3017,"stem":905,"type":46,"__hash__":3018},"docs\u002F20.connector-development\u002F20.tutorial\u002F95.build-a-sila-client.md","Build an application with SiLA",{"type":1029,"value":1030,"toc":2998},"minimark",[1031,1035,1038,1043,1056,1062,1066,1077,1093,1104,1183,1186,1190,1199,1248,1255,1319,1322,1355,1358,1365,1369,1374,1377,1408,1415,1686,1689,1703,1710,1723,1739,1758,1784,1788,1795,1902,1908,1915,1929,1932,1983,1990,1993,2013,2027,2030,2116,2119,2123,2132,2258,2261,2265,2268,2275,2436,2443,2454,2458,2465,2468,2726,2732,2762,2884,2895,2899,2906,2909,2918,2922,2984,2994],[1032,1033,1034],"p",{},"Your device is integrated. Now make something with it: a live display, an experiment queue, or an AI-driven autonomous lab. This tutorial takes you from your first SiLA client connection to the pieces of a basic application.",[1032,1036,1037],{},"This tutorial will teach the basics of making your first calls to your SiLA server using a SiLA client.",[1039,1040,1042],"h2",{"id":1041},"prerequisites","Prerequisites",[1032,1044,1045,1046,1055],{},"You need Python 3.10 or newer, Git, and ",[1047,1048,1054],"a",{"href":1049,"rel":1050,"target":1053},"https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002Fgetting-started\u002Finstallation\u002F",[1051,1052],"nofollow","noopener","_blank","uv",". The tutorial server runs entirely in source code, so you can follow along without an instrument or a UniteLabs platform account.",[1032,1057,1058,1059,1061],{},"Prefer to explore a server through an application first? ",[1047,1060,26],{"href":108}," discovers local SiLA servers and lets you read values and run operations.",[1039,1063,1065],{"id":1064},"what-connects-to-what","What connects to what?",[1067,1068,1074],"pre",{"className":1069,"code":1071,"language":1072,"meta":1073},[1070],"language-text","Your application  →  SiLA client  →  SiLA server \u002F connector  →  Instrument\n                                        │\n                                  Tutorial simulation\n","text","",[1075,1076,1071],"code",{"__ignoreMap":1073},[1032,1078,1079,1080,1084,1085,1088,1089,1092],{},"SiLA 2 describes how laboratory devices and software expose their capabilities. A ",[1081,1082,1083],"strong",{},"server"," offers those capabilities; a ",[1081,1086,1087],{},"client"," uses them. A connector often translates between SiLA and an instrument's own protocol. The ",[1047,1090,1091],{"href":848},"Connector Development Kit"," helps you build that server. Here, you will write the application that can discover and connect to it.",[1032,1094,1095,1096,1099,1100,1103],{},"Each server exposes ",[1081,1097,1098],{},"features",": named groups of properties and commands with descriptions, data types, parameters, responses and errors. Every server has a ",[1075,1101,1102],{},"SiLAService"," feature for discovering its identity and other features. The Python client can load these definitions at runtime; you do not need to generate client code for this exercise.",[1105,1106,1107,1123],"table",{},[1108,1109,1110],"thead",{},[1111,1112,1113,1117,1120],"tr",{},[1114,1115,1116],"th",{},"Interaction",[1114,1118,1119],{},"What your application does",[1114,1121,1122],{},"Tutorial example",[1124,1125,1126,1141,1155,1169],"tbody",{},[1111,1127,1128,1132,1135],{},[1129,1130,1131],"td",{},"Unobservable property",[1129,1133,1134],{},"Read one value",[1129,1136,1137,1138],{},"Read ",[1075,1139,1140],{},"Number",[1111,1142,1143,1146,1149],{},[1129,1144,1145],{},"Observable property",[1129,1147,1148],{},"Subscribe to a stream of values",[1129,1150,1151,1152],{},"Watch ",[1075,1153,1154],{},"RandomNumbers",[1111,1156,1157,1160,1163],{},[1129,1158,1159],{},"Unobservable command",[1129,1161,1162],{},"Send parameters, start an execution, and await its final response",[1129,1164,1165,1166],{},"Call ",[1075,1167,1168],{},"ParameterExample",[1111,1170,1171,1174,1177],{},[1129,1172,1173],{},"Observable command",[1129,1175,1176],{},"Send parameters, start an execution, follow progress, then retrieve its result",[1129,1178,1179,1180],{},"Run ",[1075,1181,1182],{},"IterativeMethod",[1032,1184,1185],{},"“Observable” describes the client interaction, not whether a command is permitted to change device state. An unobservable command can still perform an action on the instrument.",[1039,1187,1189],{"id":1188},"start-a-tutorial-server","Start a tutorial server",[1032,1191,1192,1193,1198],{},"In your first terminal, clone the ",[1047,1194,1197],{"href":1195,"rel":1196,"target":1053},"https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fexamples\u002Ftutorial",[1051,1052],"Tutorial Connector"," at the release this walkthrough targets.",[1067,1200,1204],{"className":1201,"code":1202,"language":1203,"meta":1073,"style":1073},"language-sh shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-default","git clone --branch v0.3.0 https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fexamples\u002Ftutorial.git tutorial\ncd tutorial\nuv sync\n","sh",[1075,1205,1206,1232,1240],{"__ignoreMap":1073},[1207,1208,1211,1215,1219,1223,1226,1229],"span",{"class":1209,"line":1210},"line",1,[1207,1212,1214],{"class":1213},"sNqAu","git",[1207,1216,1218],{"class":1217},"sCx38"," clone",[1207,1220,1222],{"class":1221},"sOiAX"," --branch",[1207,1224,1225],{"class":1217}," v0.3.0",[1207,1227,1228],{"class":1217}," https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fexamples\u002Ftutorial.git",[1207,1230,1231],{"class":1217}," tutorial\n",[1207,1233,1235,1238],{"class":1209,"line":1234},2,[1207,1236,1237],{"class":1221},"cd",[1207,1239,1231],{"class":1217},[1207,1241,1243,1245],{"class":1209,"line":1242},3,[1207,1244,1054],{"class":1213},[1207,1246,1247],{"class":1217}," sync\n",[1032,1249,1250,1251,1254],{},"Create ",[1075,1252,1253],{},"local.json"," in that directory:",[1067,1256,1260],{"className":1257,"code":1258,"filename":1253,"language":1259,"meta":1073,"style":1073},"language-json shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-default","{\n  \"sila_server\": {\n    \"hostname\": \"127.0.0.1\",\n    \"port\": 50052,\n    \"tls\": false,\n    \"name\": \"Hackathon Tutorial\"\n  },\n  \"cloud_server_endpoint\": [],\n  \"discovery\": null\n}\n","json",[1075,1261,1262,1267,1272,1277,1283,1289,1295,1301,1307,1313],{"__ignoreMap":1073},[1207,1263,1264],{"class":1209,"line":1210},[1207,1265,1266],{},"{\n",[1207,1268,1269],{"class":1209,"line":1234},[1207,1270,1271],{},"  \"sila_server\": {\n",[1207,1273,1274],{"class":1209,"line":1242},[1207,1275,1276],{},"    \"hostname\": \"127.0.0.1\",\n",[1207,1278,1280],{"class":1209,"line":1279},4,[1207,1281,1282],{},"    \"port\": 50052,\n",[1207,1284,1286],{"class":1209,"line":1285},5,[1207,1287,1288],{},"    \"tls\": false,\n",[1207,1290,1292],{"class":1209,"line":1291},6,[1207,1293,1294],{},"    \"name\": \"Hackathon Tutorial\"\n",[1207,1296,1298],{"class":1209,"line":1297},7,[1207,1299,1300],{},"  },\n",[1207,1302,1304],{"class":1209,"line":1303},8,[1207,1305,1306],{},"  \"cloud_server_endpoint\": [],\n",[1207,1308,1310],{"class":1209,"line":1309},9,[1207,1311,1312],{},"  \"discovery\": null\n",[1207,1314,1316],{"class":1209,"line":1315},10,[1207,1317,1318],{},"}\n",[1032,1320,1321],{},"Start the server and leave it running:",[1067,1323,1325],{"className":1201,"code":1324,"language":1203,"meta":1073,"style":1073},"uv run --no-sync connector start --app unitelabs.tutorial:create_app --config-path local.json\n",[1075,1326,1327],{"__ignoreMap":1073},[1207,1328,1329,1331,1334,1337,1340,1343,1346,1349,1352],{"class":1209,"line":1210},[1207,1330,1054],{"class":1213},[1207,1332,1333],{"class":1217}," run",[1207,1335,1336],{"class":1221}," --no-sync",[1207,1338,1339],{"class":1217}," connector",[1207,1341,1342],{"class":1217}," start",[1207,1344,1345],{"class":1221}," --app",[1207,1347,1348],{"class":1217}," unitelabs.tutorial:create_app",[1207,1350,1351],{"class":1221}," --config-path",[1207,1353,1354],{"class":1217}," local.json\n",[1032,1356,1357],{},"This configuration listens on your own machine, uses plaintext for the local exercise, and disables cloud connections and network announcements. No hardware is required. Stop it with Ctrl+C. If port 50052 is already occupied, pick another port and use the same value in your client.",[1032,1359,1360,1361,1364],{},"Keep server and client environments separate so the tutorial can install its own CDK and SiLA dependencies. Both client usages below use v0.12.0 of the ",[1075,1362,1363],{},"unitelabs-sila"," package. The namespace API is the default walkthrough; the optional comparison uses the unopinionated library implementation.",[1039,1366,1368],{"id":1367},"opinionated-library-implementation","Opinionated library implementation",[1370,1371,1373],"h3",{"id":1372},"connect-read-and-execute","Connect, read, and execute",[1032,1375,1376],{},"In a second terminal, create a client project alongside the tutorial directory:",[1067,1378,1380],{"className":1201,"code":1379,"language":1203,"meta":1073,"style":1073},"uv init sila-first-client\ncd sila-first-client\nuv add unitelabs-sila\n",[1075,1381,1382,1392,1398],{"__ignoreMap":1073},[1207,1383,1384,1386,1389],{"class":1209,"line":1210},[1207,1385,1054],{"class":1213},[1207,1387,1388],{"class":1217}," init",[1207,1390,1391],{"class":1217}," sila-first-client\n",[1207,1393,1394,1396],{"class":1209,"line":1234},[1207,1395,1237],{"class":1221},[1207,1397,1391],{"class":1217},[1207,1399,1400,1402,1405],{"class":1209,"line":1242},[1207,1401,1054],{"class":1213},[1207,1403,1404],{"class":1217}," add",[1207,1406,1407],{"class":1217}," unitelabs-sila\n",[1032,1409,1410,1411,1414],{},"Save this complete script as ",[1075,1412,1413],{},"first_client.py",":",[1067,1416,1420],{"className":1417,"code":1418,"filename":1413,"language":1419,"meta":1073,"style":1073},"language-python shiki shiki-themes github-light-high-contrast github-light-high-contrast github-dark-default","import asyncio\n\nfrom sila.client import Client, ClientConfig\n\n\nasync def main():\n    config = ClientConfig(\n        hostname=\"127.0.0.1\", port=50052, tls=False, default_timeout=5000\n    )\n    # Opens the connection, loads features, and closes the client on exit.\n    async with Client(config) as client:\n        print(\"Connected to:\", await client.SiLAService.ServerName.read())\n        tutorial = client.SiLAEndpointTutorialService\n        print(\"Number:\", await tutorial.Number.read())\n        result = await tutorial.ParameterExample(Seed=42)\n        print(\"Result:\", result.RandomNumber)\n\n\nif __name__ == \"__main__\":\n    asyncio.run(asyncio.wait_for(main(), timeout=20))\n","python",[1075,1421,1422,1432,1438,1451,1455,1459,1474,1485,1526,1531,1537,1555,1575,1586,1603,1628,1641,1646,1651,1669],{"__ignoreMap":1073},[1207,1423,1424,1428],{"class":1209,"line":1210},[1207,1425,1427],{"class":1426},"sxkbv","import",[1207,1429,1431],{"class":1430},"sc-9e"," asyncio\n",[1207,1433,1434],{"class":1209,"line":1234},[1207,1435,1437],{"emptyLinePlaceholder":1436},true,"\n",[1207,1439,1440,1443,1446,1448],{"class":1209,"line":1242},[1207,1441,1442],{"class":1426},"from",[1207,1444,1445],{"class":1430}," sila.client ",[1207,1447,1427],{"class":1426},[1207,1449,1450],{"class":1430}," Client, ClientConfig\n",[1207,1452,1453],{"class":1209,"line":1279},[1207,1454,1437],{"emptyLinePlaceholder":1436},[1207,1456,1457],{"class":1209,"line":1285},[1207,1458,1437],{"emptyLinePlaceholder":1436},[1207,1460,1461,1464,1467,1471],{"class":1209,"line":1291},[1207,1462,1463],{"class":1426},"async",[1207,1465,1466],{"class":1426}," def",[1207,1468,1470],{"class":1469},"s4qFZ"," main",[1207,1472,1473],{"class":1430},"():\n",[1207,1475,1476,1479,1482],{"class":1209,"line":1297},[1207,1477,1478],{"class":1430},"    config ",[1207,1480,1481],{"class":1426},"=",[1207,1483,1484],{"class":1430}," ClientConfig(\n",[1207,1486,1487,1490,1492,1495,1498,1501,1503,1506,1508,1511,1513,1516,1518,1521,1523],{"class":1209,"line":1303},[1207,1488,1489],{"class":1213},"        hostname",[1207,1491,1481],{"class":1426},[1207,1493,1494],{"class":1217},"\"127.0.0.1\"",[1207,1496,1497],{"class":1430},", ",[1207,1499,1500],{"class":1213},"port",[1207,1502,1481],{"class":1426},[1207,1504,1505],{"class":1221},"50052",[1207,1507,1497],{"class":1430},[1207,1509,1510],{"class":1213},"tls",[1207,1512,1481],{"class":1426},[1207,1514,1515],{"class":1221},"False",[1207,1517,1497],{"class":1430},[1207,1519,1520],{"class":1213},"default_timeout",[1207,1522,1481],{"class":1426},[1207,1524,1525],{"class":1221},"5000\n",[1207,1527,1528],{"class":1209,"line":1309},[1207,1529,1530],{"class":1430},"    )\n",[1207,1532,1533],{"class":1209,"line":1315},[1207,1534,1536],{"class":1535},"sIsDC","    # Opens the connection, loads features, and closes the client on exit.\n",[1207,1538,1540,1543,1546,1549,1552],{"class":1209,"line":1539},11,[1207,1541,1542],{"class":1426},"    async",[1207,1544,1545],{"class":1426}," with",[1207,1547,1548],{"class":1430}," Client(config) ",[1207,1550,1551],{"class":1426},"as",[1207,1553,1554],{"class":1430}," client:\n",[1207,1556,1558,1561,1564,1567,1569,1572],{"class":1209,"line":1557},12,[1207,1559,1560],{"class":1221},"        print",[1207,1562,1563],{"class":1430},"(",[1207,1565,1566],{"class":1217},"\"Connected to:\"",[1207,1568,1497],{"class":1430},[1207,1570,1571],{"class":1426},"await",[1207,1573,1574],{"class":1430}," client.SiLAService.ServerName.read())\n",[1207,1576,1578,1581,1583],{"class":1209,"line":1577},13,[1207,1579,1580],{"class":1430},"        tutorial ",[1207,1582,1481],{"class":1426},[1207,1584,1585],{"class":1430}," client.SiLAEndpointTutorialService\n",[1207,1587,1589,1591,1593,1596,1598,1600],{"class":1209,"line":1588},14,[1207,1590,1560],{"class":1221},[1207,1592,1563],{"class":1430},[1207,1594,1595],{"class":1217},"\"Number:\"",[1207,1597,1497],{"class":1430},[1207,1599,1571],{"class":1426},[1207,1601,1602],{"class":1430}," tutorial.Number.read())\n",[1207,1604,1606,1609,1611,1614,1617,1620,1622,1625],{"class":1209,"line":1605},15,[1207,1607,1608],{"class":1430},"        result ",[1207,1610,1481],{"class":1426},[1207,1612,1613],{"class":1426}," await",[1207,1615,1616],{"class":1430}," tutorial.ParameterExample(",[1207,1618,1619],{"class":1213},"Seed",[1207,1621,1481],{"class":1426},[1207,1623,1624],{"class":1221},"42",[1207,1626,1627],{"class":1430},")\n",[1207,1629,1631,1633,1635,1638],{"class":1209,"line":1630},16,[1207,1632,1560],{"class":1221},[1207,1634,1563],{"class":1430},[1207,1636,1637],{"class":1217},"\"Result:\"",[1207,1639,1640],{"class":1430},", result.RandomNumber)\n",[1207,1642,1644],{"class":1209,"line":1643},17,[1207,1645,1437],{"emptyLinePlaceholder":1436},[1207,1647,1649],{"class":1209,"line":1648},18,[1207,1650,1437],{"emptyLinePlaceholder":1436},[1207,1652,1654,1657,1660,1663,1666],{"class":1209,"line":1653},19,[1207,1655,1656],{"class":1426},"if",[1207,1658,1659],{"class":1221}," __name__",[1207,1661,1662],{"class":1426}," ==",[1207,1664,1665],{"class":1217}," \"__main__\"",[1207,1667,1668],{"class":1430},":\n",[1207,1670,1672,1675,1678,1680,1683],{"class":1209,"line":1671},20,[1207,1673,1674],{"class":1430},"    asyncio.run(asyncio.wait_for(main(), ",[1207,1676,1677],{"class":1213},"timeout",[1207,1679,1481],{"class":1426},[1207,1681,1682],{"class":1221},"20",[1207,1684,1685],{"class":1430},"))\n",[1032,1687,1688],{},"Run it:",[1067,1690,1692],{"className":1201,"code":1691,"language":1203,"meta":1073,"style":1073},"uv run first_client.py\n",[1075,1693,1694],{"__ignoreMap":1073},[1207,1695,1696,1698,1700],{"class":1209,"line":1210},[1207,1697,1054],{"class":1213},[1207,1699,1333],{"class":1217},[1207,1701,1702],{"class":1217}," first_client.py\n",[1032,1704,1705,1706,1709],{},"You should see the server name, a random integer from 0 to 42, and a command result of ",[1075,1707,1708],{},"0.6394267984578837"," when no other client is using the tutorial's random generator.",[1032,1711,1712,1714,1715,1718,1719,1722],{},[1075,1713,1571],{}," lets Python wait for a network response without blocking other asynchronous work. Entering ",[1075,1716,1717],{},"async with"," opens the connection and loads the feature definitions; leaving it closes the connection even when a call fails. A property returns its value. A command returns named responses: read ",[1075,1720,1721],{},"result.RandomNumber"," to access this command's result.",[1032,1724,1725,1726,1497,1728,1730,1731,1734,1735,1738],{},"Feature and parameter identifiers are case-sensitive: ",[1075,1727,1140],{},[1075,1729,1619],{},", and ",[1075,1732,1733],{},"RandomNumber"," come from the feature definition, not the server's Python method names. Accessing an attribute alone does not read a property; call and await ",[1075,1736,1737],{},".read()",".",[1032,1740,1741,1742,1745,1746,1749,1750,1753,1754,1757],{},"SiLA request timeouts such as ",[1075,1743,1744],{},"default_timeout=5000"," are ",[1081,1747,1748],{},"milliseconds",". The outer ",[1075,1751,1752],{},"asyncio.wait_for(..., timeout=20)"," is ",[1081,1755,1756],{},"seconds"," and bounds the whole example. Subscription setup timeouts do not bound the lifetime of a stream.",[1032,1759,1760,1763,1764,1767,1768,1771,1772,1775,1776,1779,1780,1783],{},[1075,1761,1762],{},"uv add unitelabs-sila"," selects the latest stable registry release for a new project. Both usages need the namespace-capable release (0.12 or newer). The starter repository records its tested registry dependencies in ",[1075,1765,1766],{},"uv.lock","; run ",[1075,1769,1770],{},"uv sync --locked"," to reproduce them. To refresh an existing checkout, run ",[1075,1773,1774],{},"uv lock --upgrade-package unitelabs-sila",". By default your dependencies will sync with the locked dependencies the next time you call ",[1075,1777,1778],{},"uv run",". You can explicitly update your environment after changing the lock with ",[1075,1781,1782],{},"uv sync",". No Git dependency or separate script environment is needed.",[1370,1785,1787],{"id":1786},"discover-and-inspect-a-different-server","Discover and inspect a different server",[1032,1789,1790,1791,1794],{},"SiLA servers can advertise themselves on the local network using mDNS\u002FDNS-SD. Save this as ",[1075,1792,1793],{},"discover.py"," in your client project:",[1067,1796,1798],{"className":1417,"code":1797,"filename":1793,"language":1419,"meta":1073,"style":1073},"import asyncio\n\nfrom sila.client.discovery import Discovery\n\n\nasync def main():\n    async with Discovery() as discovery:\n        await asyncio.sleep(8)\n        for service in discovery.services.values():\n            print(service.name, service.uuid, service.addresses, service.port)\n\n\nasyncio.run(main())\n",[1075,1799,1800,1806,1810,1822,1826,1830,1840,1854,1867,1881,1889,1893,1897],{"__ignoreMap":1073},[1207,1801,1802,1804],{"class":1209,"line":1210},[1207,1803,1427],{"class":1426},[1207,1805,1431],{"class":1430},[1207,1807,1808],{"class":1209,"line":1234},[1207,1809,1437],{"emptyLinePlaceholder":1436},[1207,1811,1812,1814,1817,1819],{"class":1209,"line":1242},[1207,1813,1442],{"class":1426},[1207,1815,1816],{"class":1430}," sila.client.discovery ",[1207,1818,1427],{"class":1426},[1207,1820,1821],{"class":1430}," Discovery\n",[1207,1823,1824],{"class":1209,"line":1279},[1207,1825,1437],{"emptyLinePlaceholder":1436},[1207,1827,1828],{"class":1209,"line":1285},[1207,1829,1437],{"emptyLinePlaceholder":1436},[1207,1831,1832,1834,1836,1838],{"class":1209,"line":1291},[1207,1833,1463],{"class":1426},[1207,1835,1466],{"class":1426},[1207,1837,1470],{"class":1469},[1207,1839,1473],{"class":1430},[1207,1841,1842,1844,1846,1849,1851],{"class":1209,"line":1297},[1207,1843,1542],{"class":1426},[1207,1845,1545],{"class":1426},[1207,1847,1848],{"class":1430}," Discovery() ",[1207,1850,1551],{"class":1426},[1207,1852,1853],{"class":1430}," discovery:\n",[1207,1855,1856,1859,1862,1865],{"class":1209,"line":1303},[1207,1857,1858],{"class":1426},"        await",[1207,1860,1861],{"class":1430}," asyncio.sleep(",[1207,1863,1864],{"class":1221},"8",[1207,1866,1627],{"class":1430},[1207,1868,1869,1872,1875,1878],{"class":1209,"line":1309},[1207,1870,1871],{"class":1426},"        for",[1207,1873,1874],{"class":1430}," service ",[1207,1876,1877],{"class":1426},"in",[1207,1879,1880],{"class":1430}," discovery.services.values():\n",[1207,1882,1883,1886],{"class":1209,"line":1315},[1207,1884,1885],{"class":1221},"            print",[1207,1887,1888],{"class":1430},"(service.name, service.uuid, service.addresses, service.port)\n",[1207,1890,1891],{"class":1209,"line":1539},[1207,1892,1437],{"emptyLinePlaceholder":1436},[1207,1894,1895],{"class":1209,"line":1557},[1207,1896,1437],{"emptyLinePlaceholder":1436},[1207,1898,1899],{"class":1209,"line":1577},[1207,1900,1901],{"class":1430},"asyncio.run(main())\n",[1032,1903,1179,1904,1907],{},[1075,1905,1906],{},"uv run discover.py",". The local tutorial configuration above deliberately disables announcements, so connect to it by its explicit address. For other devices, choose a server by UUID and confirm its identity instead of executing commands on the first discovery result.",[1032,1909,1910,1911,1914],{},"An empty result means no announcements arrived during that window. Multicast may be blocked by guest Wi-Fi, VPNs, host firewalls or VLAN boundaries. Ask the server operator for an address and port if discovery is unavailable. ",[1075,1912,1913],{},"Discovery(interface_address=\"YOUR_LOCAL_IPV4\")"," selects a particular network interface.",[1032,1916,1917,1920,1921,1924,1925,1928],{},[1075,1918,1919],{},"127.0.0.1"," and ",[1075,1922,1923],{},"localhost"," always refer to the machine running the client. Another laptop needs the server machine's reachable address. ",[1075,1926,1927],{},"0.0.0.0"," is a server bind address; do not use it as a client destination.",[1032,1930,1931],{},"Within an open client connection, inspect the server and discovered names:",[1067,1933,1935],{"className":1417,"code":1934,"language":1419,"meta":1073,"style":1073},"print(await client.SiLAService.ServerUUID.read())\nprint(await client.SiLAService.ImplementedFeatures.read())\nprint(dir(client))\nprint(dir(client.SiLAEndpointTutorialService))\n",[1075,1936,1937,1949,1960,1972],{"__ignoreMap":1073},[1207,1938,1939,1942,1944,1946],{"class":1209,"line":1210},[1207,1940,1941],{"class":1221},"print",[1207,1943,1563],{"class":1430},[1207,1945,1571],{"class":1426},[1207,1947,1948],{"class":1430}," client.SiLAService.ServerUUID.read())\n",[1207,1950,1951,1953,1955,1957],{"class":1209,"line":1234},[1207,1952,1941],{"class":1221},[1207,1954,1563],{"class":1430},[1207,1956,1571],{"class":1426},[1207,1958,1959],{"class":1430}," client.SiLAService.ImplementedFeatures.read())\n",[1207,1961,1962,1964,1966,1969],{"class":1209,"line":1242},[1207,1963,1941],{"class":1221},[1207,1965,1563],{"class":1430},[1207,1967,1968],{"class":1221},"dir",[1207,1970,1971],{"class":1430},"(client))\n",[1207,1973,1974,1976,1978,1980],{"class":1209,"line":1279},[1207,1975,1941],{"class":1221},[1207,1977,1563],{"class":1430},[1207,1979,1968],{"class":1221},[1207,1981,1982],{"class":1430},"(client.SiLAEndpointTutorialService))\n",[1032,1984,1985,1986,1989],{},"These are fragments to use inside ",[1075,1987,1988],{},"async with Client(config) as client",". On a different connector, use the identifiers it exports. The namespaces are discovered dynamically; they are not generated static Python types.",[1032,1991,1992],{},"If two features have the same short identifier, select the fully qualified identifier:",[1067,1994,1996],{"className":1417,"code":1995,"language":1419,"meta":1073,"style":1073},"tutorial = client.feature(\"io.unitelabs\u002Ftutorial\u002FSiLAEndpointTutorialService\u002Fv1\")\n",[1075,1997,1998],{"__ignoreMap":1073},[1207,1999,2000,2003,2005,2008,2011],{"class":1209,"line":1210},[1207,2001,2002],{"class":1430},"tutorial ",[1207,2004,1481],{"class":1426},[1207,2006,2007],{"class":1430}," client.feature(",[1207,2009,2010],{"class":1217},"\"io.unitelabs\u002Ftutorial\u002FSiLAEndpointTutorialService\u002Fv1\"",[1207,2012,1627],{"class":1430},[1032,2014,2015,2016,2019,2020,2022,2023,2026],{},"This selects an already-loaded feature; it does not fetch a definition. The identifier contains originator ",[1075,2017,2018],{},"io.unitelabs",", category ",[1075,2021,46],{},", feature name, and major version ",[1075,2024,2025],{},"v1",". See the unopinionated library implementation below for selective feature loading and direct endpoint inspection.",[1032,2028,2029],{},"For a TLS-enabled server, use its certificate hostname and trusted CA certificate:",[1067,2031,2033],{"className":1417,"code":2032,"language":1419,"meta":1073,"style":1073},"from pathlib import Path\n\nconfig = ClientConfig(\n    hostname=\"device.lab.example\",\n    port=50052,\n    tls=True,\n    root_certificates=Path(\"lab-ca.pem\").read_bytes(),\n)\n",[1075,2034,2035,2047,2051,2060,2073,2084,2096,2112],{"__ignoreMap":1073},[1207,2036,2037,2039,2042,2044],{"class":1209,"line":1210},[1207,2038,1442],{"class":1426},[1207,2040,2041],{"class":1430}," pathlib ",[1207,2043,1427],{"class":1426},[1207,2045,2046],{"class":1430}," Path\n",[1207,2048,2049],{"class":1209,"line":1234},[1207,2050,1437],{"emptyLinePlaceholder":1436},[1207,2052,2053,2056,2058],{"class":1209,"line":1242},[1207,2054,2055],{"class":1430},"config ",[1207,2057,1481],{"class":1426},[1207,2059,1484],{"class":1430},[1207,2061,2062,2065,2067,2070],{"class":1209,"line":1279},[1207,2063,2064],{"class":1213},"    hostname",[1207,2066,1481],{"class":1426},[1207,2068,2069],{"class":1217},"\"device.lab.example\"",[1207,2071,2072],{"class":1430},",\n",[1207,2074,2075,2078,2080,2082],{"class":1209,"line":1285},[1207,2076,2077],{"class":1213},"    port",[1207,2079,1481],{"class":1426},[1207,2081,1505],{"class":1221},[1207,2083,2072],{"class":1430},[1207,2085,2086,2089,2091,2094],{"class":1209,"line":1291},[1207,2087,2088],{"class":1213},"    tls",[1207,2090,1481],{"class":1426},[1207,2092,2093],{"class":1221},"True",[1207,2095,2072],{"class":1430},[1207,2097,2098,2101,2103,2106,2109],{"class":1209,"line":1297},[1207,2099,2100],{"class":1213},"    root_certificates",[1207,2102,1481],{"class":1426},[1207,2104,2105],{"class":1430},"Path(",[1207,2107,2108],{"class":1217},"\"lab-ca.pem\"",[1207,2110,2111],{"class":1430},").read_bytes(),\n",[1207,2113,2114],{"class":1209,"line":1303},[1207,2115,1627],{"class":1430},[1032,2117,2118],{},"Use the server's actual port and trust configuration. Turning TLS off only works when the server itself accepts plaintext. Some servers also require authentication or metadata; follow their feature definitions and the operator's setup instructions.",[1370,2120,2122],{"id":2121},"turn-readings-into-a-live-display","Turn readings into a live display",[1032,2124,2125,2126,2128,2129,2131],{},"An observable property gives you an asynchronous stream. Inside the first script's ",[1075,2127,1717],{}," block, after selecting ",[1075,2130,46],{},", add:",[1067,2133,2135],{"className":1417,"code":2134,"language":1419,"meta":1073,"style":1073},"stream = await tutorial.RandomNumbers.subscribe()\ntry:\n    for _ in range(4):\n        value = await asyncio.wait_for(anext(stream), timeout=5)\n        print(f\"{value:2d} | {'#' * value}\")\nfinally:\n    stream.close()\n",[1075,2136,2137,2149,2156,2177,2204,2246,2253],{"__ignoreMap":1073},[1207,2138,2139,2142,2144,2146],{"class":1209,"line":1210},[1207,2140,2141],{"class":1430},"stream ",[1207,2143,1481],{"class":1426},[1207,2145,1613],{"class":1426},[1207,2147,2148],{"class":1430}," tutorial.RandomNumbers.subscribe()\n",[1207,2150,2151,2154],{"class":1209,"line":1234},[1207,2152,2153],{"class":1426},"try",[1207,2155,1668],{"class":1430},[1207,2157,2158,2161,2164,2166,2169,2171,2174],{"class":1209,"line":1242},[1207,2159,2160],{"class":1426},"    for",[1207,2162,2163],{"class":1430}," _ ",[1207,2165,1877],{"class":1426},[1207,2167,2168],{"class":1221}," range",[1207,2170,1563],{"class":1430},[1207,2172,2173],{"class":1221},"4",[1207,2175,2176],{"class":1430},"):\n",[1207,2178,2179,2182,2184,2186,2189,2192,2195,2197,2199,2202],{"class":1209,"line":1279},[1207,2180,2181],{"class":1430},"        value ",[1207,2183,1481],{"class":1426},[1207,2185,1613],{"class":1426},[1207,2187,2188],{"class":1430}," asyncio.wait_for(",[1207,2190,2191],{"class":1221},"anext",[1207,2193,2194],{"class":1430},"(stream), ",[1207,2196,1677],{"class":1213},[1207,2198,1481],{"class":1426},[1207,2200,2201],{"class":1221},"5",[1207,2203,1627],{"class":1430},[1207,2205,2206,2208,2210,2213,2216,2219,2222,2225,2228,2230,2233,2236,2239,2242,2244],{"class":1209,"line":1285},[1207,2207,1560],{"class":1221},[1207,2209,1563],{"class":1430},[1207,2211,2212],{"class":1426},"f",[1207,2214,2215],{"class":1217},"\"",[1207,2217,2218],{"class":1426},"{",[1207,2220,2221],{"class":1430},"value",[1207,2223,2224],{"class":1426},":2d}",[1207,2226,2227],{"class":1217}," | ",[1207,2229,2218],{"class":1426},[1207,2231,2232],{"class":1217},"'#'",[1207,2234,2235],{"class":1426}," *",[1207,2237,2238],{"class":1430}," value",[1207,2240,2241],{"class":1426},"}",[1207,2243,2215],{"class":1217},[1207,2245,1627],{"class":1430},[1207,2247,2248,2251],{"class":1209,"line":1291},[1207,2249,2250],{"class":1426},"finally",[1207,2252,1668],{"class":1430},[1207,2254,2255],{"class":1209,"line":1297},[1207,2256,2257],{"class":1430},"    stream.close()\n",[1032,2259,2260],{},"Run the script again to see four live ASCII bars. A temperature sensor could drive the same display. The timeout bounds how long you wait for each reading; closing the stream releases the subscription. A real sensor may emit only when its value changes, so choose timeouts to match the device.",[1370,2262,2264],{"id":2263},"follow-a-running-experiment","Follow a running experiment",[1032,2266,2267],{},"An observable command returns an execution handle when the server accepts it. Acceptance is not completion. Use the handle to follow updates, wait for the terminal state and retrieve the final result.",[1032,2269,2270,2271,2128,2273,1414],{},"This fragment also belongs inside the first script's ",[1075,2272,1717],{},[1075,2274,46],{},[1067,2276,2278],{"className":1417,"code":2277,"language":1419,"meta":1073,"style":1073},"execution = await tutorial.IterativeMethod(Seed=42, NumberOfIterations=3)\ntry:\n    updates = await execution.subscribe_intermediate_responses()\n    try:\n        async for update in updates:\n            print(\"Iteration:\", update.CurrentIteration)\n    finally:\n        updates.close()\n\n    while not execution.done:\n        await asyncio.sleep(0.05)\n    result = await execution.get_responses()\n    print(\"Final result:\", result.RandomNumber)\nfinally:\n    execution.cancel()\n",[1075,2279,2280,2310,2316,2328,2335,2351,2363,2370,2375,2379,2390,2401,2413,2425,2431],{"__ignoreMap":1073},[1207,2281,2282,2285,2287,2289,2292,2294,2296,2298,2300,2303,2305,2308],{"class":1209,"line":1210},[1207,2283,2284],{"class":1430},"execution ",[1207,2286,1481],{"class":1426},[1207,2288,1613],{"class":1426},[1207,2290,2291],{"class":1430}," tutorial.IterativeMethod(",[1207,2293,1619],{"class":1213},[1207,2295,1481],{"class":1426},[1207,2297,1624],{"class":1221},[1207,2299,1497],{"class":1430},[1207,2301,2302],{"class":1213},"NumberOfIterations",[1207,2304,1481],{"class":1426},[1207,2306,2307],{"class":1221},"3",[1207,2309,1627],{"class":1430},[1207,2311,2312,2314],{"class":1209,"line":1234},[1207,2313,2153],{"class":1426},[1207,2315,1668],{"class":1430},[1207,2317,2318,2321,2323,2325],{"class":1209,"line":1242},[1207,2319,2320],{"class":1430},"    updates ",[1207,2322,1481],{"class":1426},[1207,2324,1613],{"class":1426},[1207,2326,2327],{"class":1430}," execution.subscribe_intermediate_responses()\n",[1207,2329,2330,2333],{"class":1209,"line":1279},[1207,2331,2332],{"class":1426},"    try",[1207,2334,1668],{"class":1430},[1207,2336,2337,2340,2343,2346,2348],{"class":1209,"line":1285},[1207,2338,2339],{"class":1426},"        async",[1207,2341,2342],{"class":1426}," for",[1207,2344,2345],{"class":1430}," update ",[1207,2347,1877],{"class":1426},[1207,2349,2350],{"class":1430}," updates:\n",[1207,2352,2353,2355,2357,2360],{"class":1209,"line":1291},[1207,2354,1885],{"class":1221},[1207,2356,1563],{"class":1430},[1207,2358,2359],{"class":1217},"\"Iteration:\"",[1207,2361,2362],{"class":1430},", update.CurrentIteration)\n",[1207,2364,2365,2368],{"class":1209,"line":1297},[1207,2366,2367],{"class":1426},"    finally",[1207,2369,1668],{"class":1430},[1207,2371,2372],{"class":1209,"line":1303},[1207,2373,2374],{"class":1430},"        updates.close()\n",[1207,2376,2377],{"class":1209,"line":1309},[1207,2378,1437],{"emptyLinePlaceholder":1436},[1207,2380,2381,2384,2387],{"class":1209,"line":1315},[1207,2382,2383],{"class":1426},"    while",[1207,2385,2386],{"class":1426}," not",[1207,2388,2389],{"class":1430}," execution.done:\n",[1207,2391,2392,2394,2396,2399],{"class":1209,"line":1539},[1207,2393,1858],{"class":1426},[1207,2395,1861],{"class":1430},[1207,2397,2398],{"class":1221},"0.05",[1207,2400,1627],{"class":1430},[1207,2402,2403,2406,2408,2410],{"class":1209,"line":1557},[1207,2404,2405],{"class":1430},"    result ",[1207,2407,1481],{"class":1426},[1207,2409,1613],{"class":1426},[1207,2411,2412],{"class":1430}," execution.get_responses()\n",[1207,2414,2415,2418,2420,2423],{"class":1209,"line":1577},[1207,2416,2417],{"class":1221},"    print",[1207,2419,1563],{"class":1430},[1207,2421,2422],{"class":1217},"\"Final result:\"",[1207,2424,1640],{"class":1430},[1207,2426,2427,2429],{"class":1209,"line":1588},[1207,2428,2250],{"class":1426},[1207,2430,1668],{"class":1430},[1207,2432,2433],{"class":1209,"line":1605},[1207,2434,2435],{"class":1430},"    execution.cancel()\n",[1032,2437,2438,2439,2442],{},"Keep the outer ",[1075,2440,2441],{},"asyncio.wait_for(main(), timeout=20)"," from the complete script to bound the exercise. Final-result retrieval also surfaces execution errors. Ending a stream is not proof that a command succeeded.",[1032,2444,2445,2446,2449,2450,2453],{},"In this client, ",[1075,2447,2448],{},"execution.cancel()"," closes client-side subscriptions. It does ",[1081,2451,2452],{},"not"," stop the command on the server. A timeout or disconnect can leave an operation running; inspect the device state before deciding to resubmit. Cancelling on the client never halts a device that is already moving. To stop physical motion, use the instrument's own stop mechanism or implement a dedicated SiLA stop command on the connector, and follow the device's operating procedure.",[1039,2455,2457],{"id":2456},"unopinionated-library-implementation","Unopinionated library implementation",[1032,2459,2460,2461,2464],{},"Use this when your application selects features and operations dynamically or needs precise control over loading. It uses the same ",[1075,2462,2463],{},"Client"," class and installed package as the default walkthrough.",[1032,2466,2467],{},"Here is a complete first-call example with the same inputs and responses:",[1067,2469,2472],{"className":1417,"code":2470,"filename":2471,"language":1419,"meta":1073,"style":1073},"import asyncio\n\nfrom sila.client import Client, ClientConfig\n\nFEATURE = \"io.unitelabs\u002Ftutorial\u002FSiLAEndpointTutorialService\u002Fv1\"\n\n\nasync def main():\n    config = ClientConfig(\"127.0.0.1\", 50052, tls=False, default_timeout=5000)\n    client = Client(config)\n    try:\n        await client.open(sync=False)\n        print(\"Connected to:\", await client.get_server_name())\n        feature = await client.load_feature(FEATURE)\n        print(\"Number:\", await feature.properties[\"Number\"].read())\n        result = await feature.commands[\"ParameterExample\"].execute({\"Seed\": 42})\n        print(\"Result:\", result[\"RandomNumber\"])\n    finally:\n        await client.close()\n\n\nasyncio.run(asyncio.wait_for(main(), timeout=20))\n","unopinionated_first_client.py",[1075,2473,2474,2480,2484,2494,2498,2509,2513,2517,2527,2561,2571,2577,2593,2608,2624,2645,2673,2690,2696,2703,2707,2712],{"__ignoreMap":1073},[1207,2475,2476,2478],{"class":1209,"line":1210},[1207,2477,1427],{"class":1426},[1207,2479,1431],{"class":1430},[1207,2481,2482],{"class":1209,"line":1234},[1207,2483,1437],{"emptyLinePlaceholder":1436},[1207,2485,2486,2488,2490,2492],{"class":1209,"line":1242},[1207,2487,1442],{"class":1426},[1207,2489,1445],{"class":1430},[1207,2491,1427],{"class":1426},[1207,2493,1450],{"class":1430},[1207,2495,2496],{"class":1209,"line":1279},[1207,2497,1437],{"emptyLinePlaceholder":1436},[1207,2499,2500,2503,2506],{"class":1209,"line":1285},[1207,2501,2502],{"class":1221},"FEATURE",[1207,2504,2505],{"class":1426}," =",[1207,2507,2508],{"class":1217}," \"io.unitelabs\u002Ftutorial\u002FSiLAEndpointTutorialService\u002Fv1\"\n",[1207,2510,2511],{"class":1209,"line":1291},[1207,2512,1437],{"emptyLinePlaceholder":1436},[1207,2514,2515],{"class":1209,"line":1297},[1207,2516,1437],{"emptyLinePlaceholder":1436},[1207,2518,2519,2521,2523,2525],{"class":1209,"line":1303},[1207,2520,1463],{"class":1426},[1207,2522,1466],{"class":1426},[1207,2524,1470],{"class":1469},[1207,2526,1473],{"class":1430},[1207,2528,2529,2531,2533,2536,2538,2540,2542,2544,2546,2548,2550,2552,2554,2556,2559],{"class":1209,"line":1309},[1207,2530,1478],{"class":1430},[1207,2532,1481],{"class":1426},[1207,2534,2535],{"class":1430}," ClientConfig(",[1207,2537,1494],{"class":1217},[1207,2539,1497],{"class":1430},[1207,2541,1505],{"class":1221},[1207,2543,1497],{"class":1430},[1207,2545,1510],{"class":1213},[1207,2547,1481],{"class":1426},[1207,2549,1515],{"class":1221},[1207,2551,1497],{"class":1430},[1207,2553,1520],{"class":1213},[1207,2555,1481],{"class":1426},[1207,2557,2558],{"class":1221},"5000",[1207,2560,1627],{"class":1430},[1207,2562,2563,2566,2568],{"class":1209,"line":1315},[1207,2564,2565],{"class":1430},"    client ",[1207,2567,1481],{"class":1426},[1207,2569,2570],{"class":1430}," Client(config)\n",[1207,2572,2573,2575],{"class":1209,"line":1539},[1207,2574,2332],{"class":1426},[1207,2576,1668],{"class":1430},[1207,2578,2579,2581,2584,2587,2589,2591],{"class":1209,"line":1557},[1207,2580,1858],{"class":1426},[1207,2582,2583],{"class":1430}," client.open(",[1207,2585,2586],{"class":1213},"sync",[1207,2588,1481],{"class":1426},[1207,2590,1515],{"class":1221},[1207,2592,1627],{"class":1430},[1207,2594,2595,2597,2599,2601,2603,2605],{"class":1209,"line":1577},[1207,2596,1560],{"class":1221},[1207,2598,1563],{"class":1430},[1207,2600,1566],{"class":1217},[1207,2602,1497],{"class":1430},[1207,2604,1571],{"class":1426},[1207,2606,2607],{"class":1430}," client.get_server_name())\n",[1207,2609,2610,2613,2615,2617,2620,2622],{"class":1209,"line":1588},[1207,2611,2612],{"class":1430},"        feature ",[1207,2614,1481],{"class":1426},[1207,2616,1613],{"class":1426},[1207,2618,2619],{"class":1430}," client.load_feature(",[1207,2621,2502],{"class":1221},[1207,2623,1627],{"class":1430},[1207,2625,2626,2628,2630,2632,2634,2636,2639,2642],{"class":1209,"line":1605},[1207,2627,1560],{"class":1221},[1207,2629,1563],{"class":1430},[1207,2631,1595],{"class":1217},[1207,2633,1497],{"class":1430},[1207,2635,1571],{"class":1426},[1207,2637,2638],{"class":1430}," feature.properties[",[1207,2640,2641],{"class":1217},"\"Number\"",[1207,2643,2644],{"class":1430},"].read())\n",[1207,2646,2647,2649,2651,2653,2656,2659,2662,2665,2668,2670],{"class":1209,"line":1630},[1207,2648,1608],{"class":1430},[1207,2650,1481],{"class":1426},[1207,2652,1613],{"class":1426},[1207,2654,2655],{"class":1430}," feature.commands[",[1207,2657,2658],{"class":1217},"\"ParameterExample\"",[1207,2660,2661],{"class":1430},"].execute({",[1207,2663,2664],{"class":1217},"\"Seed\"",[1207,2666,2667],{"class":1430},": ",[1207,2669,1624],{"class":1221},[1207,2671,2672],{"class":1430},"})\n",[1207,2674,2675,2677,2679,2681,2684,2687],{"class":1209,"line":1643},[1207,2676,1560],{"class":1221},[1207,2678,1563],{"class":1430},[1207,2680,1637],{"class":1217},[1207,2682,2683],{"class":1430},", result[",[1207,2685,2686],{"class":1217},"\"RandomNumber\"",[1207,2688,2689],{"class":1430},"])\n",[1207,2691,2692,2694],{"class":1209,"line":1648},[1207,2693,2367],{"class":1426},[1207,2695,1668],{"class":1430},[1207,2697,2698,2700],{"class":1209,"line":1653},[1207,2699,1858],{"class":1426},[1207,2701,2702],{"class":1430}," client.close()\n",[1207,2704,2705],{"class":1209,"line":1671},[1207,2706,1437],{"emptyLinePlaceholder":1436},[1207,2708,2710],{"class":1209,"line":2709},21,[1207,2711,1437],{"emptyLinePlaceholder":1436},[1207,2713,2715,2718,2720,2722,2724],{"class":1209,"line":2714},22,[1207,2716,2717],{"class":1430},"asyncio.run(asyncio.wait_for(main(), ",[1207,2719,1677],{"class":1213},[1207,2721,1481],{"class":1426},[1207,2723,1682],{"class":1221},[1207,2725,1685],{"class":1430},[1032,2727,2728,2729,1738],{},"Save and run ",[1075,2730,2731],{},"uv run unopinionated_first_client.py",[2733,2734,2737],"card",{"icon":2735,"title":2736},"i-heroicons-code-bracket-square","Code explanation",[1032,2738,2739,2742,2743,2746,2747,1497,2750,2753,2754,2757,2758,2761],{},[1075,2740,2741],{},"open(sync=False)"," skips loading every feature; ",[1075,2744,2745],{},"load_feature(FEATURE)"," fetches the selected definition. You can inspect ",[1075,2748,2749],{},"feature.properties",[1075,2751,2752],{},"feature.commands",", and a command's ",[1075,2755,2756],{},"parameters"," mapping. Unlike entering the context manager, calling ",[1075,2759,2760],{},"open()"," directly also lets you inspect any returned feature-load errors when synchronizing.",[1105,2763,2764,2777],{},[1108,2765,2766],{},[1111,2767,2768,2771,2774],{},[1114,2769,2770],{},"Operation",[1114,2772,2773],{},"Default usage",[1114,2775,2776],{},"unopinionated library implementation",[1124,2778,2779,2795,2810,2825,2839,2854,2869],{},[1111,2780,2781,2784,2790],{},[1129,2782,2783],{},"Select a feature",[1129,2785,2786,2789],{},[1075,2787,2788],{},"client.SiLAEndpointTutorialService"," after connection",[1129,2791,2792],{},[1075,2793,2794],{},"await client.load_feature(FEATURE)",[1111,2796,2797,2800,2805],{},[1129,2798,2799],{},"Read a property",[1129,2801,2802],{},[1075,2803,2804],{},"await tutorial.Number.read()",[1129,2806,2807],{},[1075,2808,2809],{},"await feature.properties[\"Number\"].read()",[1111,2811,2812,2815,2820],{},[1129,2813,2814],{},"Execute a command",[1129,2816,2817],{},[1075,2818,2819],{},"await tutorial.ParameterExample(Seed=42)",[1129,2821,2822],{},[1075,2823,2824],{},"await feature.commands[\"ParameterExample\"].execute({\"Seed\": 42})",[1111,2826,2827,2830,2834],{},[1129,2828,2829],{},"Read a response",[1129,2831,2832],{},[1075,2833,1721],{},[1129,2835,2836],{},[1075,2837,2838],{},"result[\"RandomNumber\"]",[1111,2840,2841,2844,2849],{},[1129,2842,2843],{},"Subscribe to values",[1129,2845,2846],{},[1075,2847,2848],{},"await tutorial.RandomNumbers.subscribe()",[1129,2850,2851],{},[1075,2852,2853],{},"await feature.properties[\"RandomNumbers\"].subscribe()",[1111,2855,2856,2859,2864],{},[1129,2857,2858],{},"Start an observable command",[1129,2860,2861],{},[1075,2862,2863],{},"await tutorial.IterativeMethod(Seed=42, NumberOfIterations=3)",[1129,2865,2866],{},[1075,2867,2868],{},"await feature.commands[\"IterativeMethod\"].execute({\"Seed\": 42, \"NumberOfIterations\": 3})",[1111,2870,2871,2874,2879],{},[1129,2872,2873],{},"Read progress",[1129,2875,2876],{},[1075,2877,2878],{},"update.CurrentIteration",[1129,2880,2881],{},[1075,2882,2883],{},"update[\"CurrentIteration\"]",[1032,2885,2886,2887,1497,2889,1730,2892,2894],{},"Subscription cleanup, execution handles, terminal-state checks, and final-response retrieval work the same way in both usages. Responses still support dictionary access. Command options ",[1075,2888,2756],{},[1075,2890,2891],{},"metadata",[1075,2893,1677],{}," are separate from device parameters: supply either a parameter dictionary or keyword parameters, not both.",[1039,2896,2898],{"id":2897},"take-it-toward-a-self-driving-lab","Take it toward a self-driving lab",[1032,2900,2901,2902,2905],{},"Start with an ",[1081,2903,2904],{},"observe → decide → act → record"," loop. Read a value, choose the next input, submit the next experiment, wait for completion and store the result with sample and execution identifiers.",[1032,2907,2908],{},"The tutorial's random scores teach the plumbing. They are not physical measurements or a meaningful optimization objective. Its random generator is shared, so concurrent tutorial calls can change seeded results. Use a simulator with a defined response surface before testing an optimization policy on an instrument.",[1032,2910,2911,2912,2917],{},"For JavaScript and web applications, see the ",[1047,2913,2916],{"href":2914,"rel":2915,"target":1053},"https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fsila2\u002Fsila-js",[1051,1052],"SiLA JS client",". Its gRPC client runs in Node.js; your browser UI can communicate with that backend over HTTP or WebSocket. Its separate framework entry point can parse feature definitions in the browser.",[1039,2919,2921],{"id":2920},"troubleshooting","Troubleshooting",[1105,2923,2924,2934],{},[1108,2925,2926],{},[1111,2927,2928,2931],{},[1114,2929,2930],{},"Symptom",[1114,2932,2933],{},"Check",[1124,2935,2936,2944,2952,2960,2968,2976],{},[1111,2937,2938,2941],{},[1129,2939,2940],{},"Connection waits or times out",[1129,2942,2943],{},"Confirm the server process, address, port and matching TLS configuration. Use bounded waits.",[1111,2945,2946,2949],{},[1129,2947,2948],{},"Discovery is empty",[1129,2950,2951],{},"Confirm announcements are enabled, select the correct interface, or use an explicit endpoint.",[1111,2953,2954,2957],{},[1129,2955,2956],{},"Unknown feature, property or parameter",[1129,2958,2959],{},"Inspect the server's definitions. Identifiers are case-sensitive and vary between connectors.",[1111,2961,2962,2965],{},[1129,2963,2964],{},"Command accepted, but no result yet",[1129,2966,2967],{},"Wait for execution completion. Retrieve final responses to detect execution errors.",[1111,2969,2970,2973],{},[1129,2971,2972],{},"Subscription is quiet",[1129,2974,2975],{},"The source may update only on change. Check the device's expected cadence and connection.",[1111,2977,2978,2981],{},[1129,2979,2980],{},"Job timed out after submission",[1129,2982,2983],{},"Its outcome may be unknown. Check state instead of automatically retrying.",[1032,2985,2986,2987,2990,2991,1738],{},"To implement your own server-side operations, continue with the ",[1047,2988,2989],{"href":880},"CDK tutorial",". To use connectors through the UniteLabs platform, see the ",[1047,2992,2993],{"href":116},"SDK and REST API guide",[2995,2996,2997],"style",{},"html pre.shiki code .sNqAu, html code.shiki .sNqAu{--shiki-light:#702C00;--shiki-default:#702C00;--shiki-dark:#FFA657}html pre.shiki code .sCx38, html code.shiki .sCx38{--shiki-light:#032563;--shiki-default:#032563;--shiki-dark:#A5D6FF}html pre.shiki code .sOiAX, html code.shiki .sOiAX{--shiki-light:#023B95;--shiki-default:#023B95;--shiki-dark:#79C0FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sxkbv, html code.shiki .sxkbv{--shiki-light:#A0111F;--shiki-default:#A0111F;--shiki-dark:#FF7B72}html pre.shiki code .sc-9e, html code.shiki .sc-9e{--shiki-light:#0E1116;--shiki-default:#0E1116;--shiki-dark:#E6EDF3}html pre.shiki code .s4qFZ, html code.shiki .s4qFZ{--shiki-light:#622CBC;--shiki-default:#622CBC;--shiki-dark:#D2A8FF}html pre.shiki code .sIsDC, html code.shiki .sIsDC{--shiki-light:#66707B;--shiki-default:#66707B;--shiki-dark:#8B949E}",{"title":1073,"searchDepth":1210,"depth":1234,"links":2999},[3000,3001,3002,3003,3009,3010,3011],{"id":1041,"depth":1234,"text":1042},{"id":1064,"depth":1234,"text":1065},{"id":1188,"depth":1234,"text":1189},{"id":1367,"depth":1234,"text":1368,"children":3004},[3005,3006,3007,3008],{"id":1372,"depth":1242,"text":1373},{"id":1786,"depth":1242,"text":1787},{"id":2121,"depth":1242,"text":2122},{"id":2263,"depth":1242,"text":2264},{"id":2456,"depth":1234,"text":2457},{"id":2897,"depth":1234,"text":2898},{"id":2920,"depth":1234,"text":2921},"Discover a SiLA server, read values, run commands, and build a small application with the Python client. A hands-on introduction for device integration hackathons.","md",{},{"title":903},"\u002Fconnector-development\u002Ftutorial\u002Fbuild-a-sila-client",{"title":1027,"description":3012},"o1ojhjD0UA3hB6KKCqjgFqQ5oxqU64V1ZHh5xbY5xl8",[3020,3022],{"title":899,"description":3021,"path":900},"Getting Started with the UniteLabs Omnibus Library for Hardware Communication",{"title":911,"description":3023,"path":912},"How UniteLabs uses the SiLA 2 standard for instrument interoperability.",1792501519664]