[{"data":1,"prerenderedAt":21691},["ShallowReactive",2],{"blog-list-en":3},[4,529,913,1164,1367,1532,1650,2448,3022,5201,6160,7992,10223,11411,13069,14983,16951,17055,17171,17460,17565,17719,17861,17981,18139,18343,18563,18723,18855,18968,19088,19243,19382,19491,19623,19723,19827,19938,20750,21026,21290],{"id":5,"title":6,"body":7,"description":510,"extension":511,"meta":512,"navigation":524,"path":525,"seo":526,"stem":527,"__hash__":528},"en_blog/en/blog/plc-to-linux-panel-transition.md","Transition from PLC Screens to Industrial Linux Panels: ZMA and GDT Integration",{"type":8,"value":9,"toc":480},"minimark",[10,15,19,23,28,39,55,59,65,79,83,87,90,96,107,112,123,127,130,136,140,151,155,159,162,170,175,202,206,212,216,229,233,237,257,262,307,311,331,335,355,359,363,366,377,383,389,392,396,400,411,415,426,430,441,445,448,459,473,476],[11,12,14],"h2",{"id":13},"introduction","Introduction",[16,17,18],"p",{},"PLC screens (Operator Panel) used for decades are reaching end-of-life. Transition to new-generation industrial Linux panels is inevitable. However, this transition requires major investment. So how can you modernize while protecting your existing investments?",[11,20,22],{"id":21},"traditional-architecture-vs-modern-architecture","Traditional Architecture vs Modern Architecture",[24,25,27],"h3",{"id":26},"old-system-10-years-ago","Old System (10+ Years Ago)",[29,30,35],"pre",{"className":31,"code":33,"language":34},[32],"language-text","PLC → Operator Panel (HMI) → Serial Communication (RS232/RS485)\n","text",[36,37,33],"code",{"__ignoreMap":38},"",[40,41,42,46,49,52],"ul",{},[43,44,45],"li",{},"Monochrome display, limited graphics",[43,47,48],{},"Closed source code",[43,50,51],{},"Difficulty finding spare parts",[43,53,54],{},"Limited connection options",[24,56,58],{"id":57},"modern-system","Modern System",[29,60,63],{"className":61,"code":62,"language":34},[32],"PLC → ZMA/GDT → Modbus TCP → Industrial Linux Panel → Cloud\n",[36,64,62],{"__ignoreMap":38},[40,66,67,70,73,76],{},[43,68,69],{},"Touch screen, high resolution",[43,71,72],{},"Open source code",[43,74,75],{},"Easy backup",[43,77,78],{},"IoT integration",[11,80,82],{"id":81},"transition-strategies","Transition Strategies",[24,84,86],{"id":85},"strategy-1-direct-replacement","Strategy 1: Direct Replacement",[16,88,89],{},"Simplest method: Remove old panel, install new Linux panel.",[16,91,92],{},[93,94,95],"strong",{},"Advantages:",[40,97,98,101,104],{},[43,99,100],{},"Full features",[43,102,103],{},"Modern UI",[43,105,106],{},"IoT ready",[16,108,109],{},[93,110,111],{},"Disadvantages:",[40,113,114,117,120],{},[43,115,116],{},"High cost",[43,118,119],{},"Software rewrite required",[43,121,122],{},"Training period",[24,124,126],{"id":125},"strategy-2-middle-layer-with-zmagdt","Strategy 2: Middle Layer (with ZMA/GDT)",[16,128,129],{},"Using Amazeng solutions for gradual transition:",[29,131,134],{"className":132,"code":133,"language":34},[32],"Old PLC + Operator Panel\n        ↓\n    ZMA/GDT Module (Bridge)\n        ↓  \n    New Linux Panel\n",[36,135,133],{"__ignoreMap":38},[16,137,138],{},[93,139,95],{},[40,141,142,145,148],{},[43,143,144],{},"Existing system preserved",[43,146,147],{},"Gradual transition",[43,149,150],{},"Low risk",[11,152,154],{"id":153},"zma-with-plc-integration","ZMA with PLC Integration",[24,156,158],{"id":157},"use-case-scenario","Use Case Scenario",[16,160,161],{},"Your old PLC system:",[40,163,164,167],{},[43,165,166],{},"Omron PLC (CP1E)",[43,168,169],{},"Touch screen (NS-10)",[16,171,172],{},[93,173,174],{},"Modernization Steps:",[176,177,178,184,190,196],"ol",{},[43,179,180,183],{},[93,181,182],{},"Add ZMA-1000",": For load cell/analog sensor data",[43,185,186,189],{},[93,187,188],{},"Add GDT",": For existing 4-20mA / 0-10V sensors",[43,191,192,195],{},[93,193,194],{},"Add Linux panel",": As new display",[43,197,198,201],{},[93,199,200],{},"Modbus TCP connection",": Between PLC and Linux panel",[24,203,205],{"id":204},"connection-diagram","Connection Diagram",[29,207,210],{"className":208,"code":209,"language":34},[32],"Old PLC ──┐\n           ├── Modbus TCP ──→ Linux Panel (ZMA/GDT data + PLC status)\nOld HMI ──┘\n",[36,211,209],{"__ignoreMap":38},[24,213,215],{"id":214},"advantages","Advantages",[40,217,218,221,224,227],{},[43,219,220],{},"PLC program unchanged",[43,222,223],{},"Existing I/O preserved",[43,225,226],{},"New features added",[43,228,147],{},[11,230,232],{"id":231},"industrial-linux-panel-options","Industrial Linux Panel Options",[24,234,236],{"id":235},"_1-qt-based-panels","1. Qt-Based Panels",[40,238,239,245,251],{},[43,240,241,244],{},[93,242,243],{},"Yocto + Qt",": Customizable UI",[43,246,247,250],{},[93,248,249],{},"Qt Designer",": Visual programming",[43,252,253,256],{},[93,254,255],{},"QML",": Modern animations",[16,258,259],{},[93,260,261],{},"ZMA Integration:",[29,263,267],{"className":264,"code":265,"language":266,"meta":38,"style":38},"language-cpp shiki shiki-themes github-light github-dark","// Qt with ZMA reading\nmodbus_t *ctx = modbus_new_tcp(\"192.168.1.100\", 502);\nmodbus_connect(ctx);\nuint16_t registers[8];\nmodbus_read_input_registers(ctx, 0, 8, registers);\n// Send to QML\n","cpp",[36,268,269,277,283,289,295,301],{"__ignoreMap":38},[270,271,274],"span",{"class":272,"line":273},"line",1,[270,275,276],{},"// Qt with ZMA reading\n",[270,278,280],{"class":272,"line":279},2,[270,281,282],{},"modbus_t *ctx = modbus_new_tcp(\"192.168.1.100\", 502);\n",[270,284,286],{"class":272,"line":285},3,[270,287,288],{},"modbus_connect(ctx);\n",[270,290,292],{"class":272,"line":291},4,[270,293,294],{},"uint16_t registers[8];\n",[270,296,298],{"class":272,"line":297},5,[270,299,300],{},"modbus_read_input_registers(ctx, 0, 8, registers);\n",[270,302,304],{"class":272,"line":303},6,[270,305,306],{},"// Send to QML\n",[24,308,310],{"id":309},"_2-hdmi-sbc-solution","2. HDMI + SBC Solution",[40,312,313,319,325],{},[43,314,315,318],{},[93,316,317],{},"Raspberry Pi 4",": Industrial use",[43,320,321,324],{},[93,322,323],{},"Docker",": Easy installation",[43,326,327,330],{},[93,328,329],{},"InfluxDB",": Data storage",[24,332,334],{"id":333},"_3-ready-hmi-solutions","3. Ready HMI Solutions",[40,336,337,343,349],{},[43,338,339,342],{},[93,340,341],{},"7\" / 10\" Touch",": Modbus TCP ready",[43,344,345,348],{},[93,346,347],{},"Python Script",": Automation",[43,350,351,354],{},[93,352,353],{},"n8n Integration",": Workflow",[11,356,358],{"id":357},"gdt-for-existing-sensor-protection","GDT for Existing Sensor Protection",[24,360,362],{"id":361},"situation-4-20ma-sensors","Situation: 4-20mA Sensors",[16,364,365],{},"Your existing 4-20mA sensors:",[40,367,368,371,374],{},[43,369,370],{},"Pressure transducers",[43,372,373],{},"Temperature sensors",[43,375,376],{},"Level sensors",[16,378,379,382],{},[93,380,381],{},"Solution:"," GDT Series",[29,384,387],{"className":385,"code":386,"language":34},[32],"4-20mA Sensor → GDT-xxx → Modbus RTU/TCP → Linux Panel\n",[36,388,386],{"__ignoreMap":38},[16,390,391],{},"GDT digital transmitter provides Modbus output while preserving your existing analog sensors.",[11,393,395],{"id":394},"transition-plan","Transition Plan",[24,397,399],{"id":398},"phase-1-preparation-month-1-2","Phase 1: Preparation (Month 1-2)",[40,401,402,405,408],{},[43,403,404],{},"Map existing system",[43,406,407],{},"Define requirements",[43,409,410],{},"Plan budget",[24,412,414],{"id":413},"phase-2-pilot-month-3-4","Phase 2: Pilot (Month 3-4)",[40,416,417,420,423],{},[43,418,419],{},"Select single line",[43,421,422],{},"ZMA/GDT integration",[43,424,425],{},"Linux panel testing",[24,427,429],{"id":428},"phase-3-full-transition-month-5-6","Phase 3: Full Transition (Month 5-6)",[40,431,432,435,438],{},[43,433,434],{},"All lines",[43,436,437],{},"Training",[43,439,440],{},"Commissioning",[11,442,444],{"id":443},"conclusion","Conclusion",[16,446,447],{},"Transition from PLC screens to industrial Linux panels is a great opportunity. With ZMA and GDT series:",[40,449,450,453,456],{},[43,451,452],{},"Existing investments protected",[43,454,455],{},"Risk minimized",[43,457,458],{},"Modern features added",[16,460,461,462,467,468,472],{},"Learn more about ",[463,464,466],"a",{"href":465},"/urunler/zma-data-acquisition","ZMA Data Acquisition"," and ",[463,469,471],{"href":470},"/urunler/gdt-dijital-transmitter","GDT Digital Transmitter",".",[474,475],"call-to-action",{},[477,478,479],"style",{},"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);}",{"title":38,"searchDepth":279,"depth":279,"links":481},[482,483,487,491,496,501,504,509],{"id":13,"depth":279,"text":14},{"id":21,"depth":279,"text":22,"children":484},[485,486],{"id":26,"depth":285,"text":27},{"id":57,"depth":285,"text":58},{"id":81,"depth":279,"text":82,"children":488},[489,490],{"id":85,"depth":285,"text":86},{"id":125,"depth":285,"text":126},{"id":153,"depth":279,"text":154,"children":492},[493,494,495],{"id":157,"depth":285,"text":158},{"id":204,"depth":285,"text":205},{"id":214,"depth":285,"text":215},{"id":231,"depth":279,"text":232,"children":497},[498,499,500],{"id":235,"depth":285,"text":236},{"id":309,"depth":285,"text":310},{"id":333,"depth":285,"text":334},{"id":357,"depth":279,"text":358,"children":502},[503],{"id":361,"depth":285,"text":362},{"id":394,"depth":279,"text":395,"children":505},[506,507,508],{"id":398,"depth":285,"text":399},{"id":413,"depth":285,"text":414},{"id":428,"depth":285,"text":429},{"id":443,"depth":279,"text":444},"Strategies for converting old PLC screens to modern industrial Linux panels, ZMA data acquisition and GDT digital transmitter integration.","md",{"date":513,"author":514,"readTime":515,"tags":516,"image":523},"2026-01-19","Amazeng Technical Team",7,[517,518,519,520,521,522],"PLC","HMI","Industrial Linux","Transition","Qt","Yocto","/blog/plc-to-linux-panel.webp",true,"/en/blog/plc-to-linux-panel-transition",{"title":6,"description":510},"en/blog/plc-to-linux-panel-transition","gZ4Ic6YXlD_l_2ch_GJXo1d2C8pLA9KezqtflhK-Zx4",{"id":530,"title":531,"body":532,"description":899,"extension":511,"meta":900,"navigation":524,"path":909,"seo":910,"stem":911,"__hash__":912},"en_blog/en/blog/tensile-test-zma.md","Tensile Testing with High-Speed Data Acquisition",{"type":8,"value":533,"toc":877},[534,536,539,543,547,573,577,597,601,605,608,628,632,635,702,706,710,716,720,745,749,809,813,817,828,832,840,844,852,854,857,868,873,875],[11,535,14],{"id":13},[16,537,538],{},"Tensile testing is a fundamental laboratory test method for determining mechanical properties of metals and alloys. Critical values such as maximum stress at fracture (MPa), elasticity modulus, and elongation percentage are measured.",[11,540,542],{"id":541},"tensile-testing-process","Tensile Testing Process",[24,544,546],{"id":545},"standard-procedure","Standard Procedure",[176,548,549,555,561,567],{},[43,550,551,554],{},[93,552,553],{},"Specimen",": Standard cylindrical specimen (typically M12 or M16 thread)",[43,556,557,560],{},[93,558,559],{},"Loading",": Controlled speed (mm/min) tension",[43,562,563,566],{},[93,564,565],{},"Recording",": Stress-strain curve",[43,568,569,572],{},[93,570,571],{},"Analysis",": Yield strength, fracture strength, % elongation",[24,574,576],{"id":575},"critical-points","Critical Points",[40,578,579,585,591],{},[43,580,581,584],{},[93,582,583],{},"Yield Point",": Where plastic deformation begins",[43,586,587,590],{},[93,588,589],{},"Maximum Load",": Peak point before fracture",[43,592,593,596],{},[93,594,595],{},"Fracture",": Moment when specimen breaks",[11,598,600],{"id":599},"problems-with-traditional-methods","Problems with Traditional Methods",[24,602,604],{"id":603},"data-loss","Data Loss",[16,606,607],{},"During tensile testing, especially at fracture moment, data loss can occur:",[40,609,610,616,622],{},[43,611,612,615],{},[93,613,614],{},"Slow Reading",": 100-200 Hz devices miss the peak",[43,617,618,621],{},[93,619,620],{},"Signal Noise",": Low-quality ADC",[43,623,624,627],{},[93,625,626],{},"Latency",": Interruption in data transfer",[24,629,631],{"id":630},"solution-zma-series","Solution: ZMA Series",[16,633,634],{},"ZMA's features are ideal for tensile testing:",[636,637,638,654],"table",{},[639,640,641],"thead",{},[642,643,644,648,651],"tr",{},[645,646,647],"th",{},"Feature",[645,649,650],{},"Value",[645,652,653],{},"For Tensile Testing",[655,656,657,669,680,691],"tbody",{},[642,658,659,663,666],{},[660,661,662],"td",{},"ADC",[660,664,665],{},"24-bit",[660,667,668],{},"Precise stress measurement",[642,670,671,674,677],{},[660,672,673],{},"Speed",[660,675,676],{},"1000 Hz",[660,678,679],{},"Captures fracture moment",[642,681,682,685,688],{},[660,683,684],{},"Connection",[660,686,687],{},"Modbus TCP",[660,689,690],{},"Linux panel integration",[642,692,693,696,699],{},[660,694,695],{},"Channels",[660,697,698],{},"Up to 8 channels",[660,700,701],{},"Multiple specimens simultaneously",[11,703,705],{"id":704},"zma-with-tensile-testing-integration","ZMA with Tensile Testing Integration",[24,707,709],{"id":708},"hardware-connection","Hardware Connection",[29,711,714],{"className":712,"code":713,"language":34},[32],"Universal Testing Machine (UTM) → Load Cell (100kN) → ZMA-1000 → Modbus TCP → Linux Panel → Database\n",[36,715,713],{"__ignoreMap":38},[24,717,719],{"id":718},"linux-panel-options","Linux Panel Options",[40,721,722,728,734,740],{},[43,723,724,727],{},[93,725,726],{},"Qt/Embedded Linux",": Real-time display",[43,729,730,733],{},[93,731,732],{},"Docker Container",": Database (InfluxDB)",[43,735,736,739],{},[93,737,738],{},"Grafana",": Historical analysis",[43,741,742,744],{},[93,743,347],{},": Automatic calculation",[24,746,748],{"id":747},"software-flow","Software Flow",[29,750,754],{"className":751,"code":752,"language":753,"meta":38,"style":38},"language-python shiki shiki-themes github-light github-dark","# ZMA data reading example\nimport pymodbus\nclient = pymodbus.TcpClient('192.168.1.100', 502)\n\nwhile True:\n    registers = client.read_input_registers(0, 8)\n    stress = registers[0] / 1000  # MPa conversion\n    strain = registers[1] / 100   # mm conversion\n    # Send to Grafana\n    influx.write(measurement=stress, tag=strain)\n","python",[36,755,756,761,766,771,776,781,786,791,797,803],{"__ignoreMap":38},[270,757,758],{"class":272,"line":273},[270,759,760],{},"# ZMA data reading example\n",[270,762,763],{"class":272,"line":279},[270,764,765],{},"import pymodbus\n",[270,767,768],{"class":272,"line":285},[270,769,770],{},"client = pymodbus.TcpClient('192.168.1.100', 502)\n",[270,772,773],{"class":272,"line":291},[270,774,775],{"emptyLinePlaceholder":524},"\n",[270,777,778],{"class":272,"line":297},[270,779,780],{},"while True:\n",[270,782,783],{"class":272,"line":303},[270,784,785],{},"    registers = client.read_input_registers(0, 8)\n",[270,787,788],{"class":272,"line":515},[270,789,790],{},"    stress = registers[0] / 1000  # MPa conversion\n",[270,792,794],{"class":272,"line":793},8,[270,795,796],{},"    strain = registers[1] / 100   # mm conversion\n",[270,798,800],{"class":272,"line":799},9,[270,801,802],{},"    # Send to Grafana\n",[270,804,806],{"class":272,"line":805},10,[270,807,808],{},"    influx.write(measurement=stress, tag=strain)\n",[11,810,812],{"id":811},"material-specific-applications","Material-Specific Applications",[24,814,816],{"id":815},"_1-steel-tensile-testing","1. Steel Tensile Testing",[40,818,819,822,825],{},[43,820,821],{},"High-strength steel (S420)",[43,823,824],{},"High stress values (500-1000 MPa)",[43,826,827],{},"ZMA's wide input range is ideal",[24,829,831],{"id":830},"_2-aluminum-tensile-testing","2. Aluminum Tensile Testing",[40,833,834,837],{},[43,835,836],{},"Lower stress values (100-300 MPa)",[43,838,839],{},"24-bit ADC provides accurate reading at low values",[24,841,843],{"id":842},"_3-composite-materials","3. Composite Materials",[40,845,846,849],{},[43,847,848],{},"Non-linear behavior",[43,850,851],{},"High speed (1kHz) captures fracture moment",[11,853,444],{"id":443},[16,855,856],{},"For accurate tensile test results:",[40,858,859,862,865],{},[43,860,861],{},"Min. 500 Hz sampling speed",[43,863,864],{},"24-bit ADC resolution",[43,866,867],{},"Modbus TCP integration",[16,869,870,871,472],{},"ZMA series meets all requirements. Modernize with ",[463,872,466],{"href":465},[474,874],{},[477,876,479],{},{"title":38,"searchDepth":279,"depth":279,"links":878},[879,880,884,888,893,898],{"id":13,"depth":279,"text":14},{"id":541,"depth":279,"text":542,"children":881},[882,883],{"id":545,"depth":285,"text":546},{"id":575,"depth":285,"text":576},{"id":599,"depth":279,"text":600,"children":885},[886,887],{"id":603,"depth":285,"text":604},{"id":630,"depth":285,"text":631},{"id":704,"depth":279,"text":705,"children":889},[890,891,892],{"id":708,"depth":285,"text":709},{"id":718,"depth":285,"text":719},{"id":747,"depth":285,"text":748},{"id":811,"depth":279,"text":812,"children":894},[895,896,897],{"id":815,"depth":285,"text":816},{"id":830,"depth":285,"text":831},{"id":842,"depth":285,"text":843},{"id":443,"depth":279,"text":444},"Metal and steel material tensile strength testing with ZMA module and industrial Linux panel integration for accurate results.",{"date":901,"author":514,"readTime":303,"tags":902,"image":908},"2026-01-18",[903,904,905,906,907],"Tensile Test","Tensile Testing","Metal Test","Steel Strength","Material Testing","/blog/tensile-test.webp","/en/blog/tensile-test-zma",{"title":531,"description":899},"en/blog/tensile-test-zma","4FUXRE8kRuxJloNkBmAaCYHaeCYHMRnQhrc4nJgqSQ0",{"id":914,"title":915,"body":916,"description":1152,"extension":511,"meta":1153,"navigation":524,"path":1160,"seo":1161,"stem":1162,"__hash__":1163},"en_blog/en/blog/marshall-stability-test-zma.md","Marshall Stability Testing with ZMA Data Acquisition",{"type":8,"value":917,"toc":1131},[918,920,923,927,931,955,959,973,977,981,1007,1009,1016,1029,1033,1037,1043,1047,1073,1077,1081,1092,1096,1107,1111,1122,1124,1129],[11,919,14],{"id":13},[16,921,922],{},"Marshall stability test is a standard method for measuring asphalt mixture strength. Bituminous mixtures are loaded until fracture under maximum load to determine stability (kN) and flow (mm) values.",[11,924,926],{"id":925},"marshall-test-summary","Marshall Test Summary",[24,928,930],{"id":929},"test-procedure","Test Procedure",[176,932,933,938,944,949],{},[43,934,935,937],{},[93,936,553],{},": 101.6mm diameter x 63.5mm cylinder",[43,939,940,943],{},[93,941,942],{},"Conditioning",": 60°C water bath for 30-40 minutes",[43,945,946,948],{},[93,947,559],{},": Loading at 50.8mm/min speed until fracture",[43,950,951,954],{},[93,952,953],{},"Measurement",": Maximum load (stability) and deformation (flow)",[24,956,958],{"id":957},"critical-values","Critical Values",[40,960,961,967],{},[43,962,963,966],{},[93,964,965],{},"Stability",": Maximum load (kN) - typically min. 8-10 kN",[43,968,969,972],{},[93,970,971],{},"Flow",": 2-4 mm - Deformation at fracture point",[11,974,976],{"id":975},"traditional-data-collection-problems","Traditional Data Collection Problems",[24,978,980],{"id":979},"manual-reading-issues","Manual Reading Issues",[176,982,983,989,995,1001],{},[43,984,985,988],{},[93,986,987],{},"Peak Missing",": Maximum load moment is very short",[43,990,991,994],{},[93,992,993],{},"Reading Error",": Difficult to read gauge quickly",[43,996,997,1000],{},[93,998,999],{},"Delay",": Must test immediately after removing from water bath",[43,1002,1003,1006],{},[93,1004,1005],{},"Recording Error",": Manual notes may be incorrect",[24,1008,631],{"id":630},[16,1010,1011,1012,1015],{},"ZMA's ",[93,1013,1014],{},"1000 Hz sampling speed",":",[40,1017,1018,1020,1023,1026],{},[43,1019,679],{},[43,1021,1022],{},"Shows real maximum value",[43,1024,1025],{},"Automatic recording",[43,1027,1028],{},"24-bit resolution for precise measurement",[11,1030,1032],{"id":1031},"zma-integration","ZMA Integration",[24,1034,1036],{"id":1035},"hardware-structure","Hardware Structure",[29,1038,1041],{"className":1039,"code":1040,"language":34},[32],"Marshall Test Device → Load Cell → ZMA Module → Modbus TCP → Industrial Panel → Database\n",[36,1042,1040],{"__ignoreMap":38},[24,1044,1046],{"id":1045},"software-layer","Software Layer",[176,1048,1049,1055,1061,1067],{},[43,1050,1051,1054],{},[93,1052,1053],{},"Linux HMI",": Real-time stability/flow graph",[43,1056,1057,1060],{},[93,1058,1059],{},"Database",": SQLite or PostgreSQL",[43,1062,1063,1066],{},[93,1064,1065],{},"Automation",": n8n report generation",[43,1068,1069,1072],{},[93,1070,1071],{},"API",": Transfer to central systems",[11,1074,1076],{"id":1075},"industrial-linux-panel-advantages","Industrial Linux Panel Advantages",[24,1078,1080],{"id":1079},"real-time-monitoring","Real-Time Monitoring",[40,1082,1083,1086,1089],{},[43,1084,1085],{},"Touch screen instant results",[43,1087,1088],{},"Load-deformation curve live",[43,1090,1091],{},"Past test results list",[24,1093,1095],{"id":1094},"reporting-automation","Reporting Automation",[40,1097,1098,1101,1104],{},[43,1099,1100],{},"Automatic PDF when test completes",[43,1102,1103],{},"Excel export format",[43,1105,1106],{},"Email sending",[24,1108,1110],{"id":1109},"quality-control","Quality Control",[40,1112,1113,1116,1119],{},[43,1114,1115],{},"Lower/upper limit setting",[43,1117,1118],{},"Out-of-spec results alert",[43,1120,1121],{},"SPC (Statistical Process Control) integration",[11,1123,444],{"id":443},[16,1125,1126,1127,472],{},"ZMA integration in Marshall testing shortens test time and increases result accuracy. Modernize your laboratory with ",[463,1128,466],{"href":465},[474,1130],{},{"title":38,"searchDepth":279,"depth":279,"links":1132},[1133,1134,1138,1142,1146,1151],{"id":13,"depth":279,"text":14},{"id":925,"depth":279,"text":926,"children":1135},[1136,1137],{"id":929,"depth":285,"text":930},{"id":957,"depth":285,"text":958},{"id":975,"depth":279,"text":976,"children":1139},[1140,1141],{"id":979,"depth":285,"text":980},{"id":630,"depth":285,"text":631},{"id":1031,"depth":279,"text":1032,"children":1143},[1144,1145],{"id":1035,"depth":285,"text":1036},{"id":1045,"depth":285,"text":1046},{"id":1075,"depth":279,"text":1076,"children":1147},[1148,1149,1150],{"id":1079,"depth":285,"text":1080},{"id":1094,"depth":285,"text":1095},{"id":1109,"depth":285,"text":1110},{"id":443,"depth":279,"text":444},"Asphalt Marshall stability and flow measurement, ZMA module with industrial Linux panel integration and accurate results.",{"date":1154,"author":514,"readTime":297,"tags":1155,"image":1159},"2026-01-17",[1156,1157,965,971,1158],"Marshall Test","Asphalt Test","Road Pavement","/blog/marshall-test.webp","/en/blog/marshall-stability-test-zma",{"title":915,"description":1152},"en/blog/marshall-stability-test-zma","f1b3v5x4N1hIG7CZSmmWRn8nEP8WscJkpDJzS7Y1noY",{"id":1165,"title":1166,"body":1167,"description":1353,"extension":511,"meta":1354,"navigation":524,"path":1363,"seo":1364,"stem":1365,"__hash__":1366},"en_blog/en/blog/cbr-test-zma.md","CBR Testing with ZMA Data Acquisition",{"type":8,"value":1168,"toc":1334},[1169,1171,1174,1178,1180,1205,1209,1220,1224,1228,1242,1246,1260,1262,1264,1270,1273,1277,1279,1298,1300,1325,1327,1332],[11,1170,14],{"id":13},[16,1172,1173],{},"California Bearing Ratio (CBR) is a standard test for measuring soil bearing capacity. Used in road, airport and railway construction to determine soil strength. Modernize your CBR testing data collection process with the ZMA series.",[11,1175,1177],{"id":1176},"what-is-cbr-testing","What is CBR Testing?",[24,1179,546],{"id":545},[176,1181,1182,1188,1194,1199],{},[43,1183,1184,1187],{},[93,1185,1186],{},"Sample Preparation",": Cylindrical sample (152mm diameter x 116mm height)",[43,1189,1190,1193],{},[93,1191,1192],{},"Penetration",": Pushing with standard piston at 2.54mm/min speed",[43,1195,1196,1198],{},[93,1197,565],{},": Load (kN) vs. Penetration (mm) curve",[43,1200,1201,1204],{},[93,1202,1203],{},"Calculation",": CBR = (Standard / Measured) x 100",[24,1206,1208],{"id":1207},"critical-data-points","Critical Data Points",[40,1210,1211,1214,1217],{},[43,1212,1213],{},"kN value at 2.5mm penetration",[43,1215,1216],{},"kN value at 5.0mm penetration",[43,1218,1219],{},"Peak load (maximum force)",[11,1221,1223],{"id":1222},"traditional-methods-vs-zma","Traditional Methods vs ZMA",[24,1225,1227],{"id":1226},"old-method","Old Method",[40,1229,1230,1233,1236,1239],{},[43,1231,1232],{},"Manual data recording",[43,1234,1235],{},"Graph paper reading",[43,1237,1238],{},"Manual Excel transfer",[43,1240,1241],{},"Time waste: 15-20 minutes per test",[24,1243,1245],{"id":1244},"zma-solution","ZMA Solution",[40,1247,1248,1251,1254,1257],{},[43,1249,1250],{},"Automatic data recording",[43,1252,1253],{},"Instant graphic display",[43,1255,1256],{},"Modbus TCP transfer to Linux panel",[43,1258,1259],{},"Test time: 3-5 minutes",[11,1261,1032],{"id":1031},[24,1263,205],{"id":204},[29,1265,1268],{"className":1266,"code":1267,"language":34},[32],"Load Cell → ZMA-1000 → Modbus TCP → Industrial Panel (Linux) → Automation Software\n",[36,1269,1267],{"__ignoreMap":38},[16,1271,1272],{},"ZMA's 24-bit ADC resolution provides accurate readings even at low load values. 1000 Hz sampling speed plots detailed penetration curve.",[11,1274,1276],{"id":1275},"laboratory-integration","Laboratory Integration",[24,1278,719],{"id":718},[40,1280,1281,1287,1293],{},[43,1282,1283,1286],{},[93,1284,1285],{},"Qt-Based HMI",": Touch screen with instant monitoring",[43,1288,1289,1292],{},[93,1290,1291],{},"SCADA Connection",": Central database transfer",[43,1294,1295,1297],{},[93,1296,1065],{},": Processing test results with n8n or Node-RED",[24,1299,215],{"id":214},[176,1301,1302,1307,1313,1319],{},[43,1303,1304,1306],{},[93,1305,673],{},": Data automatically recorded",[43,1308,1309,1312],{},[93,1310,1311],{},"Accuracy",": Human error elimination",[43,1314,1315,1318],{},[93,1316,1317],{},"Reporting",": Automatic CBR report",[43,1320,1321,1324],{},[93,1322,1323],{},"Archiving",": Historical database",[11,1326,444],{"id":443},[16,1328,1329,1330,472],{},"ZMA integration in CBR tests increases laboratory efficiency by 3-4 times. Modernize with ",[463,1331,466],{"href":465},[474,1333],{},{"title":38,"searchDepth":279,"depth":279,"links":1335},[1336,1337,1341,1345,1348,1352],{"id":13,"depth":279,"text":14},{"id":1176,"depth":279,"text":1177,"children":1338},[1339,1340],{"id":545,"depth":285,"text":546},{"id":1207,"depth":285,"text":1208},{"id":1222,"depth":279,"text":1223,"children":1342},[1343,1344],{"id":1226,"depth":285,"text":1227},{"id":1244,"depth":285,"text":1245},{"id":1031,"depth":279,"text":1032,"children":1346},[1347],{"id":204,"depth":285,"text":205},{"id":1275,"depth":279,"text":1276,"children":1349},[1350,1351],{"id":718,"depth":285,"text":719},{"id":214,"depth":285,"text":215},{"id":443,"depth":279,"text":444},"California Bearing Ratio testing with ZMA module and industrial Linux panel integration for laboratory efficiency.",{"date":1355,"author":514,"readTime":297,"tags":1356,"image":1362},"2026-01-16",[1357,1358,1359,1360,1361],"CBR Test","Soil Test","California Bearing Ratio","ZMA","Road Construction","/blog/cbr-test.webp","/en/blog/cbr-test-zma",{"title":1166,"description":1353},"en/blog/cbr-test-zma","0z12kcRwFnBSXqo5J871FlK--igBc0vJXxrGkL6_8GU",{"id":1368,"title":1369,"body":1370,"description":1520,"extension":511,"meta":1521,"navigation":524,"path":1528,"seo":1529,"stem":1530,"__hash__":1531},"en_blog/en/blog/concrete-press-test-zma.md","High-Speed Data Acquisition in Concrete Compression Tests",{"type":8,"value":1371,"toc":1507},[1372,1374,1377,1381,1385,1388,1393,1404,1408,1415,1419,1421,1447,1449,1455,1458,1462,1486,1488,1491,1500,1505],[11,1373,14],{"id":13},[16,1375,1376],{},"Concrete compression strength testing is one of the most critical quality control processes in the construction industry. Cube concrete specimens are crushed after 7, 28 or 90 days to determine maximum compressive strength (MPa). However, the accuracy of these tests depends not only on the press machine quality but also directly on the data acquisition system speed.",[11,1378,1380],{"id":1379},"data-collection-challenges-in-press-testing","Data Collection Challenges in Press Testing",[24,1382,1384],{"id":1383},"dynamic-fracture-moment","Dynamic Fracture Moment",[16,1386,1387],{},"When a concrete specimen fractures, this fracture occurs in as little as one-thousandth of a second. Standard data acquisition devices cannot capture this speed and produce incorrect results.",[16,1389,1390],{},[93,1391,1392],{},"Problematic Scenario:",[40,1394,1395,1398,1401],{},[43,1396,1397],{},"Standard reading: 150 Hz (150 samples per second)",[43,1399,1400],{},"Fracture moment: \u003C5 milliseconds",[43,1402,1403],{},"Result: Peak point is missed, strength value appears lower",[24,1405,1407],{"id":1406},"solution-high-speed-adc","Solution: High-Speed ADC",[16,1409,1410,1411,1414],{},"Amazeng ZMA series captures the fracture moment with ",[93,1412,1413],{},"1000 Hz (1kHz)"," sampling speed. This speed accurately plots the concrete fracture curve.",[11,1416,1418],{"id":1417},"zma-with-press-testing-integration","ZMA with Press Testing Integration",[24,1420,709],{"id":708},[176,1422,1423,1429,1435,1441],{},[43,1424,1425,1428],{},[93,1426,1427],{},"LVDT Sensor",": Mounted on specimen",[43,1430,1431,1434],{},[93,1432,1433],{},"Load Cell",": Integrated into press table",[43,1436,1437,1440],{},[93,1438,1439],{},"ZMA Module",": Collects sensor data",[43,1442,1443,1446],{},[93,1444,1445],{},"Industrial Linux Panel",": Displays results",[24,1448,748],{"id":747},[29,1450,1453],{"className":1451,"code":1452,"language":34},[32],"Press Machine → Load Cell → ZMA (1kHz) → Modbus TCP → Linux Panel (HMI) → Result Display\n",[36,1454,1452],{"__ignoreMap":38},[16,1456,1457],{},"ZMA's Modbus TCP output connects directly to industrial Linux panels (embedded Linux, Qt, Yocto).",[11,1459,1461],{"id":1460},"why-industrial-linux-panel","Why Industrial Linux Panel?",[40,1463,1464,1470,1475,1480],{},[43,1465,1466,1469],{},[93,1467,1468],{},"Real-Time Display",": Instant pressure value",[43,1471,1472,1474],{},[93,1473,1059],{},": Historical test results",[43,1476,1477,1479],{},[93,1478,1317],{},": PDF output",[43,1481,1482,1485],{},[93,1483,1484],{},"Network Connection",": Central monitoring",[11,1487,444],{"id":443},[16,1489,1490],{},"For accurate concrete press test results:",[40,1492,1493,1495,1497],{},[43,1494,861],{},[43,1496,864],{},[43,1498,1499],{},"Industrial Linux integration",[16,1501,1502,1503,472],{},"ZMA series meets all these requirements. Learn more about ",[463,1504,466],{"href":465},[474,1506],{},{"title":38,"searchDepth":279,"depth":279,"links":1508},[1509,1510,1514,1518,1519],{"id":13,"depth":279,"text":14},{"id":1379,"depth":279,"text":1380,"children":1511},[1512,1513],{"id":1383,"depth":285,"text":1384},{"id":1406,"depth":285,"text":1407},{"id":1417,"depth":279,"text":1418,"children":1515},[1516,1517],{"id":708,"depth":285,"text":709},{"id":747,"depth":285,"text":748},{"id":1460,"depth":279,"text":1461},{"id":443,"depth":279,"text":444},"Millisecond-precision data collection in concrete press testing, ZMA series industrial Linux panel integration, and critical factors for accurate results.",{"date":1522,"author":514,"readTime":303,"tags":1523,"image":1527},"2026-01-15",[1524,1525,1526,1360,519],"Concrete Test","Press Test","Compressive Strength","/blog/concrete-press-test.webp","/en/blog/concrete-press-test-zma",{"title":1369,"description":1520},"en/blog/concrete-press-test-zma","W9jQIyZc0gjq1pGkDRwZR8DKnZetpGFFnz3X4x3a2O8",{"id":1533,"title":1534,"body":1535,"description":1637,"extension":511,"meta":1638,"navigation":524,"path":1646,"seo":1647,"stem":1648,"__hash__":1649},"en_blog/en/blog/tinyml-ai-revolution-industrial-sensors.md","TinyML: The Edge AI Revolution in Industrial Sensors",{"type":8,"value":1536,"toc":1630},[1537,1539,1546,1550,1553,1573,1577,1597,1601,1604,1618,1620,1623],[11,1538,14],{"id":13},[16,1540,1541,1542,1545],{},"When we think of artificial intelligence, massive servers and powerful GPUs come to mind. However, an industrial transmitter or vibration sensor in the field doesn't have access to such computational power. This is where ",[93,1543,1544],{},"TinyML (Tiny Machine Learning)"," comes into play. TinyML is the art of running machine learning models on microcontrollers (MCUs) with just a few kilobytes of memory. This technology transforms industrial sensors from simple data collectors into intelligent devices that understand what they see.",[11,1547,1549],{"id":1548},"what-does-tinyml-change-in-sensors","What Does TinyML Change in Sensors?",[16,1551,1552],{},"Traditional sensors collect and transmit data. A smart sensor with TinyML:",[176,1554,1555,1561,1567],{},[43,1556,1557,1560],{},[93,1558,1559],{},"Local Decision Making",": Analyzes data on-device without sending it to the cloud. This means zero-latency response times measured in milliseconds.",[43,1562,1563,1566],{},[93,1564,1565],{},"Bandwidth Savings",": Transmits data only when an abnormal condition (failure, leak, etc.) is detected. This reduces energy and communication costs for IoT systems.",[43,1568,1569,1572],{},[93,1570,1571],{},"Privacy and Security",": Cybersecurity risks are minimized since critical data is processed without leaving the device.",[11,1574,1576],{"id":1575},"industrial-application-examples","Industrial Application Examples",[40,1578,1579,1585,1591],{},[43,1580,1581,1584],{},[93,1582,1583],{},"Anomaly Detection",": Can detect a previously unseen failure mode from a motor's vibration within seconds.",[43,1586,1587,1590],{},[93,1588,1589],{},"Intelligent Filtering",": Uses deep learning models instead of classical filters to distinguish between noise and real data (e.g., tank sloshing vs. actual fill level changes).",[43,1592,1593,1596],{},[93,1594,1595],{},"Audio Analysis",": Sound-based analysis systems that can determine which bearing needs lubrication from the sounds machines make in a factory.",[11,1598,1600],{"id":1599},"amazeng-and-the-ai-powered-future","Amazeng and the AI-Powered Future",[16,1602,1603],{},"At Amazeng, we're making our data acquisition devices \"Edge AI\" compatible.",[40,1605,1606,1615],{},[43,1607,1608,1609,1614],{},"The 24-bit high-resolution data from our ",[93,1610,1611],{},[463,1612,466],{"href":1613},"/en/products/zma-data-acquisition"," devices provides the highest quality training material for TinyML models.",[43,1616,1617],{},"The modern MCU infrastructure we use in our embedded system architecture enables libraries like TensorFlow Lite Micro and Edge Impulse to run on our devices.",[11,1619,444],{"id":443},[16,1621,1622],{},"TinyML is a silent revolution that increases the \"IQ\" of industrial sensors. In the factories of the future, devices won't just be connected to each other; each will have its own small artificial intelligence in its area of responsibility.",[16,1624,1625,1626,472],{},"For more information about our AI-powered sensor projects and TinyML-based solutions, ",[463,1627,1629],{"href":1628},"/en/contact","contact our engineers",{"title":38,"searchDepth":279,"depth":279,"links":1631},[1632,1633,1634,1635,1636],{"id":13,"depth":279,"text":14},{"id":1548,"depth":279,"text":1549},{"id":1575,"depth":279,"text":1576},{"id":1599,"depth":279,"text":1600},{"id":443,"depth":279,"text":444},"TinyML brings the art of running artificial intelligence on resource-constrained microcontrollers (MCUs) and its transformative power in industrial sensors.",{"date":1639,"author":514,"readTime":303,"tags":1640},"2026-01-02",[1641,1642,1643,1644,1645],"TinyML","Edge AI","Industrial Sensors","Artificial Intelligence","Embedded Systems","/en/blog/tinyml-ai-revolution-industrial-sensors",{"title":1534,"description":1637},"en/blog/tinyml-ai-revolution-industrial-sensors","qGOEQT4YK1HlmYk8hn6fbBnoomVHINGhPY9VIyhuvuw",{"id":1651,"title":1652,"body":1653,"description":2435,"extension":511,"meta":2436,"navigation":524,"path":2444,"seo":2445,"stem":2446,"__hash__":2447},"en_blog/en/blog/grafana-industrial-data-visualization.md","Industrial Data Visualization with Grafana: Real-Time Monitoring and Dashboard Design",{"type":8,"value":1654,"toc":2398},[1655,1657,1663,1666,1670,1673,1699,1703,1706,1712,1716,1725,1736,1740,1743,1767,1771,1774,1806,1810,1813,1817,1834,1838,1858,1862,1877,1881,1896,1900,1903,1983,1987,1991,2022,2026,2058,2062,2136,2140,2146,2150,2154,2165,2169,2180,2184,2187,2193,2197,2257,2263,2267,2274,2285,2289,2293,2296,2300,2303,2309,2313,2316,2320,2327,2342,2346,2349,2362,2367,2371,2395],[11,1656,14],{"id":13},[16,1658,1659,1660,1662],{},"In industrial facilities, data flows from dozens of sensors every second: temperature, pressure, weight, vibration... However, if this data is not made meaningful, it remains just \"numbers.\" This is where ",[93,1661,738],{}," stands out as the most powerful open-source tool for visualizing and making industrial data meaningful.",[16,1664,1665],{},"In this article, we'll cover how to use Grafana in industrial IoT projects, its integration with our ZMA/GDT devices, and professional dashboard design.",[11,1667,1669],{"id":1668},"what-is-grafana","What is Grafana?",[16,1671,1672],{},"Grafana is an open-source platform used to visualize data from time-series databases (InfluxDB, Prometheus, TimescaleDB, Amazon Timestream, etc.). It's particularly preferred in IoT and industrial monitoring systems because:",[40,1674,1675,1681,1687,1693],{},[43,1676,1677,1680],{},[93,1678,1679],{},"Real-Time Data Flow",": Can update at millisecond intervals.",[43,1682,1683,1686],{},[93,1684,1685],{},"Flexible Dashboard Design",": Create rich visualization panels with drag-and-drop.",[43,1688,1689,1692],{},[93,1690,1691],{},"Alarm System",": Generates automatic alarms at defined threshold values (email, Slack, Telegram, etc.).",[43,1694,1695,1698],{},[93,1696,1697],{},"Multiple Data Sources",": Can combine multiple databases in a single dashboard.",[11,1700,1702],{"id":1701},"grafana-architecture-for-industrial-iot","Grafana Architecture for Industrial IoT",[16,1704,1705],{},"A typical industrial Grafana integration works like this:",[29,1707,1710],{"className":1708,"code":1709,"language":34},[32],"ZMA/GDT Devices → MQTT/Modbus → IoT Gateway → Time Series DB (InfluxDB) → Grafana Dashboard\n",[36,1711,1709],{"__ignoreMap":38},[24,1713,1715],{"id":1714},"_1-data-collection-zma-and-gdt","1. Data Collection: ZMA and GDT",[16,1717,1718,1719,467,1721,1724],{},"Our ",[463,1720,466],{"href":1613},[463,1722,471],{"href":1723},"/en/products/gdt-digital-transmitter"," devices:",[40,1726,1727,1730,1733],{},[43,1728,1729],{},"Collect high-precision data with 24-bit resolution",[43,1731,1732],{},"Communicate via Modbus RTU/TCP",[43,1734,1735],{},"Transmit to cloud/local servers via MQTT or HTTP",[24,1737,1739],{"id":1738},"_2-time-series-database","2. Time Series Database",[16,1741,1742],{},"Data sources that work best with Grafana:",[40,1744,1745,1750,1761],{},[43,1746,1747,1749],{},[93,1748,329],{},": Open-source, high-performance time-series DB",[43,1751,1752,1755,1756,1760],{},[93,1753,1754],{},"Amazon Timestream",": Cloud-based, managed service (",[463,1757,1759],{"href":1758},"/en/blog/time-series-data-management-amazon-timestream","Our Amazon Timestream article",")",[43,1762,1763,1766],{},[93,1764,1765],{},"TimescaleDB",": PostgreSQL-based time-series extension",[24,1768,1770],{"id":1769},"_3-grafana-dashboard","3. Grafana Dashboard",[16,1772,1773],{},"Dashboards consist of different panels:",[40,1775,1776,1782,1788,1794,1800],{},[43,1777,1778,1781],{},[93,1779,1780],{},"Graph Panel",": Time series charts",[43,1783,1784,1787],{},[93,1785,1786],{},"Gauge Panel",": Instant value indicator (RPM, temperature, etc.)",[43,1789,1790,1793],{},[93,1791,1792],{},"Stat Panel",": Single numerical value display",[43,1795,1796,1799],{},[93,1797,1798],{},"Table Panel",": Tabular data display",[43,1801,1802,1805],{},[93,1803,1804],{},"Heatmap",": Density maps",[11,1807,1809],{"id":1808},"real-world-application-weighing-system-dashboard","Real-World Application: Weighing System Dashboard",[16,1811,1812],{},"Example Grafana dashboard structure for a milk tank monitoring system:",[24,1814,1816],{"id":1815},"panel-1-current-weight-gauge","Panel 1: Current Weight (Gauge)",[29,1818,1822],{"className":1819,"code":1820,"language":1821,"meta":38,"style":38},"language-sql shiki shiki-themes github-light github-dark","SELECT last(\"weight\") FROM \"tank_data\"\nWHERE (\"device_id\" = 'GDT-001') AND time > now() - 5m\n","sql",[36,1823,1824,1829],{"__ignoreMap":38},[270,1825,1826],{"class":272,"line":273},[270,1827,1828],{},"SELECT last(\"weight\") FROM \"tank_data\"\n",[270,1830,1831],{"class":272,"line":279},[270,1832,1833],{},"WHERE (\"device_id\" = 'GDT-001') AND time > now() - 5m\n",[24,1835,1837],{"id":1836},"panel-2-fill-trend-graph","Panel 2: Fill Trend (Graph)",[29,1839,1841],{"className":1819,"code":1840,"language":1821,"meta":38,"style":38},"SELECT mean(\"weight\") FROM \"tank_data\"\nWHERE time > now() - 24h\nGROUP BY time(10m)\n",[36,1842,1843,1848,1853],{"__ignoreMap":38},[270,1844,1845],{"class":272,"line":273},[270,1846,1847],{},"SELECT mean(\"weight\") FROM \"tank_data\"\n",[270,1849,1850],{"class":272,"line":279},[270,1851,1852],{},"WHERE time > now() - 24h\n",[270,1854,1855],{"class":272,"line":285},[270,1856,1857],{},"GROUP BY time(10m)\n",[24,1859,1861],{"id":1860},"panel-3-temperature-monitoring","Panel 3: Temperature Monitoring",[29,1863,1865],{"className":1819,"code":1864,"language":1821,"meta":38,"style":38},"SELECT \"temperature\" FROM \"sensor_data\"\nWHERE (\"sensor_id\" = 'ZMA-TEMP-01') AND time > now() - 1h\n",[36,1866,1867,1872],{"__ignoreMap":38},[270,1868,1869],{"class":272,"line":273},[270,1870,1871],{},"SELECT \"temperature\" FROM \"sensor_data\"\n",[270,1873,1874],{"class":272,"line":279},[270,1875,1876],{},"WHERE (\"sensor_id\" = 'ZMA-TEMP-01') AND time > now() - 1h\n",[24,1878,1880],{"id":1879},"panel-4-alarm-status-stat-panel","Panel 4: Alarm Status (Stat Panel)",[29,1882,1884],{"className":1819,"code":1883,"language":1821,"meta":38,"style":38},"SELECT count(\"alarm\") FROM \"alerts\"\nWHERE time > now() - 1h\n",[36,1885,1886,1891],{"__ignoreMap":38},[270,1887,1888],{"class":272,"line":273},[270,1889,1890],{},"SELECT count(\"alarm\") FROM \"alerts\"\n",[270,1892,1893],{"class":272,"line":279},[270,1894,1895],{},"WHERE time > now() - 1h\n",[11,1897,1899],{"id":1898},"grafana-alert-configuration","Grafana Alert Configuration",[16,1901,1902],{},"Automatic alarm setup for critical situations:",[29,1904,1908],{"className":1905,"code":1906,"language":1907,"meta":38,"style":38},"language-yaml shiki shiki-themes github-light github-dark","alert:\n  name: \"Tank Overflow Warning\"\n  condition:\n    - query: SELECT last(\"weight\") FROM \"tank_data\"\n    - threshold: > 950 kg\n  notification:\n    - email: alarm@factory.com\n    - telegram: @factory_alarms\n","yaml",[36,1909,1910,1920,1932,1939,1951,1968,1973,1978],{"__ignoreMap":38},[270,1911,1912,1916],{"class":272,"line":273},[270,1913,1915],{"class":1914},"s9eBZ","alert",[270,1917,1919],{"class":1918},"sVt8B",":\n",[270,1921,1922,1925,1928],{"class":272,"line":279},[270,1923,1924],{"class":1914},"  name",[270,1926,1927],{"class":1918},": ",[270,1929,1931],{"class":1930},"sZZnC","\"Tank Overflow Warning\"\n",[270,1933,1934,1937],{"class":272,"line":285},[270,1935,1936],{"class":1914},"  condition",[270,1938,1919],{"class":1918},[270,1940,1941,1944,1947,1949],{"class":272,"line":291},[270,1942,1943],{"class":1918},"    - ",[270,1945,1946],{"class":1914},"query",[270,1948,1927],{"class":1918},[270,1950,1828],{"class":1930},[270,1952,1953,1955,1958,1960,1964],{"class":272,"line":297},[270,1954,1943],{"class":1918},[270,1956,1957],{"class":1914},"threshold",[270,1959,1927],{"class":1918},[270,1961,1963],{"class":1962},"szBVR",">",[270,1965,1967],{"class":1966},"s7hpK"," 950 kg\n",[270,1969,1970],{"class":272,"line":303},[270,1971,1972],{"class":1930},"  notification:\n",[270,1974,1975],{"class":272,"line":515},[270,1976,1977],{"class":1930},"    - email: alarm@factory.com\n",[270,1979,1980],{"class":272,"line":793},[270,1981,1982],{"class":1930},"    - telegram: @factory_alarms\n",[11,1984,1986],{"id":1985},"zmagdt-integration-with-grafana","ZMA/GDT Integration with Grafana",[24,1988,1990],{"id":1989},"step-1-mqtt-broker-setup","Step 1: MQTT Broker Setup",[29,1992,1996],{"className":1993,"code":1994,"language":1995,"meta":38,"style":38},"language-bash shiki shiki-themes github-light github-dark","# Mosquitto MQTT broker installation\nsudo apt-get install mosquitto mosquitto-clients\n","bash",[36,1997,1998,2004],{"__ignoreMap":38},[270,1999,2000],{"class":272,"line":273},[270,2001,2003],{"class":2002},"sJ8bj","# Mosquitto MQTT broker installation\n",[270,2005,2006,2010,2013,2016,2019],{"class":272,"line":279},[270,2007,2009],{"class":2008},"sScJk","sudo",[270,2011,2012],{"class":1930}," apt-get",[270,2014,2015],{"class":1930}," install",[270,2017,2018],{"class":1930}," mosquitto",[270,2020,2021],{"class":1930}," mosquitto-clients\n",[24,2023,2025],{"id":2024},"step-2-influxdb-installation","Step 2: InfluxDB Installation",[29,2027,2029],{"className":1993,"code":2028,"language":1995,"meta":38,"style":38},"# InfluxDB 2.x installation\nwget https://dl.influxdata.com/influxdb/releases/influxdb2-2.7.1-amd64.deb\nsudo dpkg -i influxdb2-2.7.1-amd64.deb\n",[36,2030,2031,2036,2044],{"__ignoreMap":38},[270,2032,2033],{"class":272,"line":273},[270,2034,2035],{"class":2002},"# InfluxDB 2.x installation\n",[270,2037,2038,2041],{"class":272,"line":279},[270,2039,2040],{"class":2008},"wget",[270,2042,2043],{"class":1930}," https://dl.influxdata.com/influxdb/releases/influxdb2-2.7.1-amd64.deb\n",[270,2045,2046,2048,2051,2055],{"class":272,"line":285},[270,2047,2009],{"class":2008},[270,2049,2050],{"class":1930}," dpkg",[270,2052,2054],{"class":2053},"sj4cs"," -i",[270,2056,2057],{"class":1930}," influxdb2-2.7.1-amd64.deb\n",[24,2059,2061],{"id":2060},"step-3-data-flow-with-node-red","Step 3: Data Flow with Node-RED",[29,2063,2067],{"className":2064,"code":2065,"language":2066,"meta":38,"style":38},"language-javascript shiki shiki-themes github-light github-dark","// Writing ZMA data from MQTT to InfluxDB\nmsg.payload = {\n  measurement: 'sensor_data',\n  tags: {\n    device_id: msg.topic.split('/')[1],\n  },\n  fields: {\n    weight: parseFloat(msg.payload.weight),\n    temperature: parseFloat(msg.payload.temp),\n  },\n  timestamp: new Date(),\n}\nreturn msg\n","javascript",[36,2068,2069,2074,2079,2084,2089,2094,2099,2104,2109,2114,2118,2124,2130],{"__ignoreMap":38},[270,2070,2071],{"class":272,"line":273},[270,2072,2073],{},"// Writing ZMA data from MQTT to InfluxDB\n",[270,2075,2076],{"class":272,"line":279},[270,2077,2078],{},"msg.payload = {\n",[270,2080,2081],{"class":272,"line":285},[270,2082,2083],{},"  measurement: 'sensor_data',\n",[270,2085,2086],{"class":272,"line":291},[270,2087,2088],{},"  tags: {\n",[270,2090,2091],{"class":272,"line":297},[270,2092,2093],{},"    device_id: msg.topic.split('/')[1],\n",[270,2095,2096],{"class":272,"line":303},[270,2097,2098],{},"  },\n",[270,2100,2101],{"class":272,"line":515},[270,2102,2103],{},"  fields: {\n",[270,2105,2106],{"class":272,"line":793},[270,2107,2108],{},"    weight: parseFloat(msg.payload.weight),\n",[270,2110,2111],{"class":272,"line":799},[270,2112,2113],{},"    temperature: parseFloat(msg.payload.temp),\n",[270,2115,2116],{"class":272,"line":805},[270,2117,2098],{},[270,2119,2121],{"class":272,"line":2120},11,[270,2122,2123],{},"  timestamp: new Date(),\n",[270,2125,2127],{"class":272,"line":2126},12,[270,2128,2129],{},"}\n",[270,2131,2133],{"class":272,"line":2132},13,[270,2134,2135],{},"return msg\n",[24,2137,2139],{"id":2138},"step-4-grafana-data-source-configuration","Step 4: Grafana Data Source Configuration",[29,2141,2144],{"className":2142,"code":2143,"language":34},[32],"URL: http://localhost:8086\nOrganization: amazeng\nToken: [InfluxDB API Token]\nDefault Bucket: industrial_data\n",[36,2145,2143],{"__ignoreMap":38},[11,2147,2149],{"id":2148},"dashboard-design-tips","Dashboard Design Tips",[24,2151,2153],{"id":2152},"_1-color-coding","1. Color Coding",[40,2155,2156,2159,2162],{},[43,2157,2158],{},"🟢 Green: Normal operation (0-80%)",[43,2160,2161],{},"🟡 Yellow: Caution (80-95%)",[43,2163,2164],{},"🔴 Red: Critical (95-100%)",[24,2166,2168],{"id":2167},"_2-panel-organization","2. Panel Organization",[40,2170,2171,2174,2177],{},[43,2172,2173],{},"Top row: Instant values (Gauge, Stat)",[43,2175,2176],{},"Middle section: Trend graphs (Graph)",[43,2178,2179],{},"Bottom section: Alarm logs (Table)",[24,2181,2183],{"id":2182},"_3-variable-usage","3. Variable Usage",[16,2185,2186],{},"Add dynamism to your dashboard:",[29,2188,2191],{"className":2189,"code":2190,"language":34},[32],"$device_id = InfluxDB Query: SHOW TAG VALUES WITH KEY = \"device_id\"\n",[36,2192,2190],{"__ignoreMap":38},[11,2194,2196],{"id":2195},"grafana-cloud-vs-self-hosted","Grafana Cloud vs. Self-Hosted",[636,2198,2199,2211],{},[639,2200,2201],{},[642,2202,2203,2205,2208],{},[645,2204,647],{},[645,2206,2207],{},"Grafana Cloud",[645,2209,2210],{},"Self-Hosted",[655,2212,2213,2224,2235,2246],{},[642,2214,2215,2218,2221],{},[660,2216,2217],{},"Cost",[660,2219,2220],{},"Limited free, then paid",[660,2222,2223],{},"Server cost only",[642,2225,2226,2229,2232],{},[660,2227,2228],{},"Maintenance",[660,2230,2231],{},"None",[660,2233,2234],{},"Updates and backups required",[642,2236,2237,2240,2243],{},[660,2238,2239],{},"Performance",[660,2241,2242],{},"High",[660,2244,2245],{},"Hardware-dependent",[642,2247,2248,2251,2254],{},[660,2249,2250],{},"Data Control",[660,2252,2253],{},"In cloud",[660,2255,2256],{},"On-premise",[16,2258,2259,2262],{},[93,2260,2261],{},"Amazeng Recommendation",": Self-hosted InfluxDB + Grafana setup for critical data.",[11,2264,2266],{"id":2265},"example-dashboard-zma-desk-integration","Example Dashboard: ZMA Desk Integration",[16,2268,2269,2270,2273],{},"You can visualize data generated by our ",[463,2271,2272],{"href":1613},"ZMA Desk"," software in Grafana:",[176,2275,2276,2279,2282],{},[43,2277,2278],{},"ZMA Desk → CSV/JSON export",[43,2280,2281],{},"Transfer to InfluxDB via Telegraf",[43,2283,2284],{},"Create custom dashboard in Grafana",[11,2286,2288],{"id":2287},"advanced-features","Advanced Features",[24,2290,2292],{"id":2291},"_1-annotations","1. Annotations",[16,2294,2295],{},"Mark important events (maintenance, failures, etc.) on the timeline.",[24,2297,2299],{"id":2298},"_2-variables-and-templating","2. Variables and Templating",[16,2301,2302],{},"Monitor all devices with a single dashboard:",[29,2304,2307],{"className":2305,"code":2306,"language":34},[32],"SELECT * FROM \"data\" WHERE \"device_id\" = '$device'\n",[36,2308,2306],{"__ignoreMap":38},[24,2310,2312],{"id":2311},"_3-grafana-loki-log-management","3. Grafana Loki (Log Management)",[16,2314,2315],{},"Search and analyze device logs within Grafana.",[11,2317,2319],{"id":2318},"real-project-fully-integrated-solution","Real Project: Fully Integrated Solution",[16,2321,1718,2322,2326],{},[463,2323,2325],{"href":2324},"/en/blog/fully-integrated-solution-zma-gdt-hmi-aws","fully integrated weighing system"," offered by Amazeng:",[40,2328,2329,2332,2335],{},[43,2330,2331],{},"GDT → Modbus → ZMA → MQTT → InfluxDB → Grafana",[43,2333,2334],{},"HMI Panel (local) + Grafana (remote monitoring)",[43,2336,2337,2338],{},"Cloud integration with ",[463,2339,2341],{"href":2340},"/en/blog/industrial-data-collection-with-aws-iot-core","AWS IoT Core",[11,2343,2345],{"id":2344},"conclusion-and-recommendations","Conclusion and Recommendations",[16,2347,2348],{},"Grafana is a powerful tool that makes industrial data meaningful and accelerates decision-making processes. When integrated with our ZMA and GDT devices:",[16,2350,2351,2352,2355,2356,2358,2359,2361],{},"✅ Real-time factory monitoring",[2353,2354],"br",{},"\n✅ Proactive maintenance (predictive maintenance)",[2353,2357],{},"\n✅ Data-driven decision making",[2353,2360],{},"\n✅ Remote access and mobile monitoring",[16,2363,2364,2365,472],{},"For more information about Grafana-based monitoring systems and ZMA/GDT integration, ",[463,2366,1629],{"href":1628},[11,2368,2370],{"id":2369},"related-articles","Related Articles",[40,2372,2373,2378,2383,2389],{},[43,2374,2375],{},[463,2376,2377],{"href":1758},"Time Series Data Management with Amazon Timestream",[43,2379,2380],{},[463,2381,2382],{"href":2340},"Industrial Data Collection with AWS IoT Core",[43,2384,2385],{},[463,2386,2388],{"href":2387},"/en/blog/industrial-iot-automation-with-n8n","Industrial IoT Automation with n8n",[43,2390,2391],{},[463,2392,2394],{"href":2393},"/en/blog/zma-desk-monitoring-and-datalog-features","ZMA Desk Monitoring and Datalog Features",[477,2396,2397],{},"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 .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":38,"searchDepth":279,"depth":279,"links":2399},[2400,2401,2402,2407,2413,2414,2420,2425,2426,2427,2432,2433,2434],{"id":13,"depth":279,"text":14},{"id":1668,"depth":279,"text":1669},{"id":1701,"depth":279,"text":1702,"children":2403},[2404,2405,2406],{"id":1714,"depth":285,"text":1715},{"id":1738,"depth":285,"text":1739},{"id":1769,"depth":285,"text":1770},{"id":1808,"depth":279,"text":1809,"children":2408},[2409,2410,2411,2412],{"id":1815,"depth":285,"text":1816},{"id":1836,"depth":285,"text":1837},{"id":1860,"depth":285,"text":1861},{"id":1879,"depth":285,"text":1880},{"id":1898,"depth":279,"text":1899},{"id":1985,"depth":279,"text":1986,"children":2415},[2416,2417,2418,2419],{"id":1989,"depth":285,"text":1990},{"id":2024,"depth":285,"text":2025},{"id":2060,"depth":285,"text":2061},{"id":2138,"depth":285,"text":2139},{"id":2148,"depth":279,"text":2149,"children":2421},[2422,2423,2424],{"id":2152,"depth":285,"text":2153},{"id":2167,"depth":285,"text":2168},{"id":2182,"depth":285,"text":2183},{"id":2195,"depth":279,"text":2196},{"id":2265,"depth":279,"text":2266},{"id":2287,"depth":279,"text":2288,"children":2428},[2429,2430,2431],{"id":2291,"depth":285,"text":2292},{"id":2298,"depth":285,"text":2299},{"id":2311,"depth":285,"text":2312},{"id":2318,"depth":279,"text":2319},{"id":2344,"depth":279,"text":2345},{"id":2369,"depth":279,"text":2370},"How to visualize industrial IoT data with Grafana, create meaningful dashboards, and set up real-time monitoring systems. Grafana integration with ZMA and GDT devices.",{"date":2437,"author":514,"readTime":793,"tags":2438},"2026-01-01",[738,2439,2440,2441,2442,329,2443],"Data Visualization","Dashboard","IoT","Monitoring","Time Series","/en/blog/grafana-industrial-data-visualization",{"title":1652,"description":2435},"en/blog/grafana-industrial-data-visualization","5IZMzCdvnoTuT8YqFoYaniAm9USRB0q_B2SPH6jD47k",{"id":2449,"title":2450,"body":2451,"description":3009,"extension":511,"meta":3010,"navigation":524,"path":3018,"seo":3019,"stem":3020,"__hash__":3021},"en_blog/en/blog/7-inch-and-10-1-inch-hmi-screens-right-size-selection.md","7 Inch and 10.1 Inch HMI Screens: Choosing the Right Size for Industrial Applications",{"type":8,"value":2452,"toc":2984},[2453,2455,2466,2470,2473,2498,2502,2506,2526,2528,2534,2540,2546,2552,2556,2578,2582,2585,2602,2605,2614,2620,2626,2637,2640,2660,2664,2771,2775,2778,2792,2795,2809,2813,2822,2854,2858,2862,2877,2881,2896,2900,2903,2914,2919,2941,2944,2946,2952,2961,2965],[11,2454,14],{"id":13},[16,2456,2457,2458,2461,2462,472],{},"In industrial automation, ",[93,2459,2460],{},"HMI (Human Machine Interface)"," screens are the most critical communication point between the operator and the machine. However, one of the most frequently asked questions when selecting an HMI is: \"Should I get a 7 inch or 10.1 inch?\" In this article, we examine all criteria for selecting the right screen size within our ",[463,2463,2465],{"href":2464},"/en/solutions/hmi-industrial-display-solutions","HMI Industrial Display Solutions",[11,2467,2469],{"id":2468},"why-screen-size-matters","Why Screen Size Matters",[16,2471,2472],{},"HMI screen size is not just a physical preference; it directly affects:",[40,2474,2475,2481,2487,2493],{},[43,2476,2477,2480],{},[93,2478,2479],{},"Operator ergonomics",": Viewing distance and touch accessibility",[43,2482,2483,2486],{},[93,2484,2485],{},"Information density",": Number of parameters displayed on screen",[43,2488,2489,2492],{},[93,2490,2491],{},"Mounting space",": Space constraints in the machine panel",[43,2494,2495,2497],{},[93,2496,2217],{},": Investment proportional to screen size",[11,2499,2501],{"id":2500},"_7-inch-hmi-screens-compact-and-efficient","7 Inch HMI Screens: Compact and Efficient",[24,2503,2505],{"id":2504},"technical-specifications","Technical Specifications",[40,2507,2508,2514,2520],{},[43,2509,2510,2513],{},[93,2511,2512],{},"Resolution",": Typically 800x480 pixels",[43,2515,2516,2519],{},[93,2517,2518],{},"Display Area",": ~155mm x 87mm",[43,2521,2522,2525],{},[93,2523,2524],{},"Mounting Size",": Suitable for compact panels (~190mm x 120mm cutout)",[24,2527,215],{"id":214},[16,2529,2530,2533],{},[93,2531,2532],{},"1. Compatibility with Narrow Panels","\nIn compact machines (e.g., small packaging machines, dosing units), panel space is limited. 7 inch screens are the ideal solution for such applications.",[16,2535,2536,2539],{},[93,2537,2538],{},"2. Close Distance Usage","\nIf the operator is 30-50cm from the screen, a 7 inch display is large enough to comfortably view all information.",[16,2541,2542,2545],{},[93,2543,2544],{},"3. Low Power Consumption","\nSmaller screen = less backlight = lower power consumption. Preferred for battery-powered or mobile applications.",[16,2547,2548,2551],{},[93,2549,2550],{},"4. Cost Advantage","\n20-30% more economical compared to 10.1 inch screens.",[24,2553,2555],{"id":2554},"use-case-scenarios","Use Case Scenarios",[40,2557,2558,2566,2572],{},[43,2559,2560,1927,2563,2565],{},[93,2561,2562],{},"Weighing Systems",[463,2564,471],{"href":1723}," + 7\" HMI for loadcell reading and tare operations",[43,2567,2568,2571],{},[93,2569,2570],{},"Filling Machines",": Simple start/stop, setpoint adjustments",[43,2573,2574,2577],{},[93,2575,2576],{},"Compact Control Panels",": Field-type measurement and control units",[11,2579,2581],{"id":2580},"_101-inch-hmi-screens-wide-view-and-detailed-data","10.1 Inch HMI Screens: Wide View and Detailed Data",[24,2583,2505],{"id":2584},"technical-specifications-1",[40,2586,2587,2592,2597],{},[43,2588,2589,2591],{},[93,2590,2512],{},": Typically 1024x600 or 1280x800 pixels",[43,2593,2594,2596],{},[93,2595,2518],{},": ~222mm x 125mm",[43,2598,2599,2601],{},[93,2600,2524],{},": Suitable for medium-large panels (~260mm x 180mm cutout)",[24,2603,215],{"id":2604},"advantages-1",[16,2606,2607,2610,2611,2613],{},[93,2608,2609],{},"1. Multi-Parameter Applications","\nWith data acquisition systems like ",[463,2612,466],{"href":1613}," devices with 4 channels, live graphs and numerical values of all channels can be displayed simultaneously.",[16,2615,2616,2619],{},[93,2617,2618],{},"2. Long Distance Visibility","\nIf the operator is 1-2 meters from the screen (e.g., in large machines), a 10.1 inch screen is more readable.",[16,2621,2622,2625],{},[93,2623,2624],{},"3. Graphics and Trend Analysis","\nMore suitable for detailed data visualization such as real-time graphs, alarm history, production reports.",[16,2627,2628,2631,2632,2636],{},[93,2629,2630],{},"4. Future Expansion","\nEven if the application is simple initially, it leaves room for features to be added later (e.g., ",[463,2633,2635],{"href":2634},"/en/solutions/cloud-iot-data-collection","Cloud IoT Data Collection"," integration).",[24,2638,2555],{"id":2639},"use-case-scenarios-1",[40,2641,2642,2648,2654],{},[43,2643,2644,2647],{},[93,2645,2646],{},"Milk Tank Control",": Multi-tank level, temperature, mixer status",[43,2649,2650,2653],{},[93,2651,2652],{},"Production Line Monitoring",": 4-8 station status, OEE metrics",[43,2655,2656,2659],{},[93,2657,2658],{},"Batch Processing",": Recipe management, step-by-step procedures",[11,2661,2663],{"id":2662},"comparison-table","Comparison Table",[636,2665,2666,2679],{},[639,2667,2668],{},[642,2669,2670,2673,2676],{},[645,2671,2672],{},"Criteria",[645,2674,2675],{},"7 Inch HMI",[645,2677,2678],{},"10.1 Inch HMI",[655,2680,2681,2694,2707,2720,2733,2746,2758],{},[642,2682,2683,2688,2691],{},[660,2684,2685],{},[93,2686,2687],{},"Viewing Distance",[660,2689,2690],{},"30-50 cm",[660,2692,2693],{},"50-200 cm",[642,2695,2696,2701,2704],{},[660,2697,2698],{},[93,2699,2700],{},"Max Parameters",[660,2702,2703],{},"4-6 values",[660,2705,2706],{},"10-15 values",[642,2708,2709,2714,2717],{},[660,2710,2711],{},[93,2712,2713],{},"Graphics Display",[660,2715,2716],{},"Simple bar/trend",[660,2718,2719],{},"Multiple graphs + tables",[642,2721,2722,2727,2730],{},[660,2723,2724],{},[93,2725,2726],{},"Mounting Area",[660,2728,2729],{},"190x120 mm",[660,2731,2732],{},"260x180 mm",[642,2734,2735,2740,2743],{},[660,2736,2737],{},[93,2738,2739],{},"Power Consumption",[660,2741,2742],{},"~3-5W",[660,2744,2745],{},"~8-12W",[642,2747,2748,2752,2755],{},[660,2749,2750],{},[93,2751,2217],{},[660,2753,2754],{},"⭐⭐⭐ Economical",[660,2756,2757],{},"⭐⭐ Medium",[642,2759,2760,2765,2768],{},[660,2761,2762],{},[93,2763,2764],{},"Touch Target",[660,2766,2767],{},"Min 10mm button",[660,2769,2770],{},"Min 8mm button",[11,2772,2774],{"id":2773},"hybrid-approach-multi-screen-solutions","Hybrid Approach: Multi-Screen Solutions",[16,2776,2777],{},"In some applications, both screen types can be used together:",[40,2779,2780,2786],{},[43,2781,2782,2785],{},[93,2783,2784],{},"Main Control Panel",": 10.1 inch screen (central control room)",[43,2787,2788,2791],{},[93,2789,2790],{},"Machine-Side Screens",": 7 inch screens (local control at each station)",[16,2793,2794],{},"For example, in a milk processing facility:",[40,2796,2797,2803,2806],{},[43,2798,2799,2800],{},"Operator room: 10.1\" screen + ",[463,2801,2802],{"href":2634},"Cloud monitoring dashboard",[43,2804,2805],{},"Filling line: 7\" screen (start/stop, emergency stop)",[43,2807,2808],{},"Packaging: 7\" screen (piece counting, label approval)",[11,2810,2812],{"id":2811},"advantages-of-our-linux-based-hmi-solutions","Advantages of Our Linux-Based HMI Solutions",[16,2814,1718,2815,2817,2818,2821],{},[463,2816,2465],{"href":2464}," come with ",[93,2819,2820],{},"Embedded Linux"," operating system in both 7 inch and 10.1 inch models. This provides:",[40,2823,2824,2830,2842,2848],{},[43,2825,2826,2829],{},[93,2827,2828],{},"Customizable Interface",": Develop your own UI with Qt/QML",[43,2831,2832,2835,2836,467,2838,2841],{},[93,2833,2834],{},"Modbus RTU/TCP Support",": Direct communication with our ",[463,2837,1360],{"href":1613},[463,2839,2840],{"href":1723},"GDT"," products",[43,2843,2844,2847],{},[93,2845,2846],{},"Cloud Integration",": MQTT connection to AWS IoT Core (both 7\" and 10.1\")",[43,2849,2850,2853],{},[93,2851,2852],{},"OTA Updates",": Remote software updates",[11,2855,2857],{"id":2856},"selection-guide-which-is-right-for-you","Selection Guide: Which is Right for You?",[24,2859,2861],{"id":2860},"choose-7-inch-if","Choose 7 Inch If:",[16,2863,2864,2865,2867,2868,2870,2871,2873,2874,2876],{},"✅ Machine panel space is limited (\u003C 200mm width)",[2353,2866],{},"\n✅ Few parameters to display (1-4 values)",[2353,2869],{},"\n✅ Operator very close to screen (\u003C 50cm)",[2353,2872],{},"\n✅ Budget optimization is priority",[2353,2875],{},"\n✅ Mobile/portable application",[24,2878,2880],{"id":2879},"choose-101-inch-if","Choose 10.1 Inch If:",[16,2882,2883,2884,2886,2887,2889,2890,2892,2893,2895],{},"✅ Panel space is sufficient (> 260mm width)",[2353,2885],{},"\n✅ Multi-parameter system (4+ channels)",[2353,2888],{},"\n✅ Graphics and trend analysis required",[2353,2891],{},"\n✅ Operator monitors from distance (> 1m)",[2353,2894],{},"\n✅ System may expand in future",[11,2897,2899],{"id":2898},"real-world-example-milk-tank-application","Real-World Example: Milk Tank Application",[16,2901,2902],{},"One of our customers has 3 milk tanks of 5000 liters each. Each tank has:",[40,2904,2905,2908,2911],{},[43,2906,2907],{},"4 loadcells (weight measurement)",[43,2909,2910],{},"2 temperature sensors",[43,2912,2913],{},"1 level sensor",[16,2915,2916],{},[93,2917,2918],{},"Solution Architecture:",[40,2920,2921,2929,2935],{},[43,2922,2923,2928],{},[93,2924,2925,2926],{},"1 ",[463,2927,471],{"href":1723}," per tank (4 loadcell inputs)",[43,2930,2931,2934],{},[93,2932,2933],{},"1x 10.1\" HMI"," for central control (displays all tanks)",[43,2936,2937,2940],{},[93,2938,2939],{},"1x 7\" HMI"," per tank (detailed control of that tank)",[16,2942,2943],{},"The operator monitors all tanks from the 10.1\" screen in the office, while during tanker loading, can perform tare and net weight reading from the 7\" screen at the relevant tank.",[11,2945,2345],{"id":2344},[16,2947,2948,2949,472],{},"HMI screen size selection should be based on application needs. 7 inch and 10.1 inch screens are optimized for different scenarios and are not alternatives to each other, but ",[93,2950,2951],{},"complementary",[16,2953,2954,2955,2957,2958,472],{},"For detailed information about our ",[463,2956,2465],{"href":2464}," and to determine the most suitable size for your application, ",[463,2959,2960],{"href":1628},"contact our technical team",[24,2962,2964],{"id":2963},"related-solutions","Related Solutions",[40,2966,2967,2971,2975,2979],{},[43,2968,2969],{},[463,2970,2465],{"href":2464},[43,2972,2973],{},[463,2974,466],{"href":1613},[43,2976,2977],{},[463,2978,471],{"href":1723},[43,2980,2981],{},[463,2982,2983],{"href":2634},"Cloud & IoT Data Collection",{"title":38,"searchDepth":279,"depth":279,"links":2985},[2986,2987,2988,2993,2998,2999,3000,3001,3005,3006],{"id":13,"depth":279,"text":14},{"id":2468,"depth":279,"text":2469},{"id":2500,"depth":279,"text":2501,"children":2989},[2990,2991,2992],{"id":2504,"depth":285,"text":2505},{"id":214,"depth":285,"text":215},{"id":2554,"depth":285,"text":2555},{"id":2580,"depth":279,"text":2581,"children":2994},[2995,2996,2997],{"id":2584,"depth":285,"text":2505},{"id":2604,"depth":285,"text":215},{"id":2639,"depth":285,"text":2555},{"id":2662,"depth":279,"text":2663},{"id":2773,"depth":279,"text":2774},{"id":2811,"depth":279,"text":2812},{"id":2856,"depth":279,"text":2857,"children":3002},[3003,3004],{"id":2860,"depth":285,"text":2861},{"id":2879,"depth":285,"text":2880},{"id":2898,"depth":279,"text":2899},{"id":2344,"depth":279,"text":2345,"children":3007},[3008],{"id":2963,"depth":285,"text":2964},"Comprehensive guide for selecting 7 inch vs 10.1 inch HMI screens based on machine size, operator ergonomics, and viewing distance.",{"date":3011,"author":514,"readTime":793,"tags":3012},"2025-12-29",[518,3013,3014,3015,3016,3017],"7 inch screen","10.1 inch screen","Industrial Display","Touchscreen","Operator Interface","/en/blog/7-inch-and-10-1-inch-hmi-screens-right-size-selection",{"title":2450,"description":3009},"en/blog/7-inch-and-10-1-inch-hmi-screens-right-size-selection","IRFwtRidr3oyQY12VmoGyPU9m-Cwqe6XK19aCs6BB3w",{"id":3023,"title":3024,"body":3025,"description":5189,"extension":511,"meta":5190,"navigation":524,"path":5197,"seo":5198,"stem":5199,"__hash__":5200},"en_blog/en/blog/aws-bedrock-industrial-generative-ai.md","Generative AI in Industrial Data with AWS Bedrock",{"type":8,"value":3026,"toc":5156},[3027,3029,3043,3051,3055,3060,3064,3163,3167,3277,3281,3287,3291,3295,3301,3305,3796,3801,3888,3892,3895,3902,3906,4199,4203,4206,4209,4213,4505,4509,4513,4520,4878,4882,4886,4950,4954,4960,4971,4976,4982,4988,4992,4996,5063,5068,5082,5084,5089,5115,5121,5129,5133,5153],[11,3028,14],{"id":13},[16,3030,3031,3034,3035,3038,3039,3042],{},[93,3032,3033],{},"Generative AI"," is revolutionizing not only chatbots and content generation but also ",[93,3036,3037],{},"industrial data analysis",". ",[93,3040,3041],{},"AWS Bedrock"," provides serverless access to advanced foundation models like Claude, Llama, and Amazon Titan without model training.",[16,3044,3045,3046,467,3048,3050],{},"In this article, we examine how to analyze data from our ",[463,3047,466],{"href":1613},[463,3049,471],{"href":1723}," devices using AWS Bedrock for predictive maintenance and reporting.",[11,3052,3054],{"id":3053},"what-is-aws-bedrock","What is AWS Bedrock?",[16,3056,3057,3059],{},[93,3058,3041],{}," is a fully managed service offering access to foundation models (FMs) from leading AI companies via API.",[24,3061,3063],{"id":3062},"available-models","Available Models",[636,3065,3066,3082],{},[639,3067,3068],{},[642,3069,3070,3073,3076,3079],{},[645,3071,3072],{},"Model",[645,3074,3075],{},"Provider",[645,3077,3078],{},"Parameters",[645,3080,3081],{},"Strengths",[655,3083,3084,3100,3115,3131,3147],{},[642,3085,3086,3091,3094,3097],{},[660,3087,3088],{},[93,3089,3090],{},"Claude 3.5 Sonnet",[660,3092,3093],{},"Anthropic",[660,3095,3096],{},"175B",[660,3098,3099],{},"Complex reasoning, coding",[642,3101,3102,3107,3109,3112],{},[660,3103,3104],{},[93,3105,3106],{},"Claude 3 Haiku",[660,3108,3093],{},[660,3110,3111],{},"20B",[660,3113,3114],{},"Fast, cost-effective",[642,3116,3117,3122,3125,3128],{},[660,3118,3119],{},[93,3120,3121],{},"Llama 3.1",[660,3123,3124],{},"Meta",[660,3126,3127],{},"8B-405B",[660,3129,3130],{},"Open source, multilingual",[642,3132,3133,3138,3141,3144],{},[660,3134,3135],{},[93,3136,3137],{},"Amazon Titan",[660,3139,3140],{},"AWS",[660,3142,3143],{},"-",[660,3145,3146],{},"Text generation, embedding",[642,3148,3149,3154,3157,3160],{},[660,3150,3151],{},[93,3152,3153],{},"Mistral Large",[660,3155,3156],{},"Mistral AI",[660,3158,3159],{},"123B",[660,3161,3162],{},"Multilingual, specialized",[24,3164,3166],{"id":3165},"bedrock-vs-alternatives","Bedrock vs Alternatives",[636,3168,3169,3183],{},[639,3170,3171],{},[642,3172,3173,3175,3177,3180],{},[645,3174,647],{},[645,3176,3041],{},[645,3178,3179],{},"OpenAI API",[645,3181,3182],{},"Self-Hosted (Ollama)",[655,3184,3185,3201,3217,3232,3246,3262],{},[642,3186,3187,3192,3195,3198],{},[660,3188,3189],{},[93,3190,3191],{},"Deployment",[660,3193,3194],{},"Serverless",[660,3196,3197],{},"Cloud API",[660,3199,3200],{},"Local infrastructure",[642,3202,3203,3208,3211,3214],{},[660,3204,3205],{},[93,3206,3207],{},"Data Privacy",[660,3209,3210],{},"AWS VPC",[660,3212,3213],{},"Data leaves facility",[660,3215,3216],{},"Fully local",[642,3218,3219,3223,3226,3229],{},[660,3220,3221],{},[93,3222,626],{},[660,3224,3225],{},"200-500ms",[660,3227,3228],{},"300-800ms",[660,3230,3231],{},"50-200ms",[642,3233,3234,3238,3241,3243],{},[660,3235,3236],{},[93,3237,2217],{},[660,3239,3240],{},"Pay-per-token",[660,3242,3240],{},[660,3244,3245],{},"Hardware only",[642,3247,3248,3253,3256,3259],{},[660,3249,3250],{},[93,3251,3252],{},"Model Selection",[660,3254,3255],{},"10+ models",[660,3257,3258],{},"5 models",[660,3260,3261],{},"Limited (7B-13B)",[642,3263,3264,3269,3272,3274],{},[660,3265,3266],{},[93,3267,3268],{},"Fine-tuning",[660,3270,3271],{},"✅ Supported",[660,3273,3271],{},[660,3275,3276],{},"⚠️ Manual",[11,3278,3280],{"id":3279},"system-architecture","System Architecture",[29,3282,3285],{"className":3283,"code":3284,"language":34},[32],"┌───────────────────────────────────────────────┐\n│           Factory Network                     │\n│                                               │\n│  ┌─────────┐   Modbus   ┌──────────────┐     │\n│  │ ZMA/GDT │───────────►│  IoT Gateway │     │\n│  │ Devices │            └──────┬───────┘     │\n└────────────────────────────────┼─────────────┘\n                                 │ MQTT/TLS\n                                 ▼\n                    ┌────────────────────────┐\n                    │      AWS Cloud         │\n                    │                        │\n                    │  ┌──────────────────┐  │\n                    │  │   IoT Core       │  │\n                    │  └────────┬─────────┘  │\n                    │           │            │\n                    │  ┌────────▼─────────┐  │\n                    │  │   Timestream     │  │\n                    │  │   (Raw Data)     │  │\n                    │  └────────┬─────────┘  │\n                    │           │            │\n                    │  ┌────────▼─────────┐  │\n                    │  │   Lambda         │  │\n                    │  │   (Processor)    │  │\n                    │  └────────┬─────────┘  │\n                    │           │            │\n                    │  ┌────────▼─────────┐  │\n                    │  │  AWS Bedrock     │  │\n                    │  │                  │  │\n                    │  │  • Claude 3.5    │  │\n                    │  │  • Llama 3.1     │  │\n                    │  │  • Titan         │  │\n                    │  └────────┬─────────┘  │\n                    │           │            │\n                    │  ┌────────▼─────────┐  │\n                    │  │   S3 Bucket      │  │\n                    │  │   (Reports)      │  │\n                    │  └──────────────────┘  │\n                    └────────────────────────┘\n",[36,3286,3284],{"__ignoreMap":38},[11,3288,3290],{"id":3289},"application-1-anomaly-detection-with-ai","Application 1: Anomaly Detection with AI",[24,3292,3294],{"id":3293},"scenario","Scenario",[16,3296,3297,3298,3300],{},"Detect abnormal patterns in loadcell data from ",[463,3299,2840],{"href":1723}," that might indicate tank tilt or sensor failure.",[24,3302,3304],{"id":3303},"lambda-function-with-claude","Lambda Function with Claude",[29,3306,3308],{"className":751,"code":3307,"language":753,"meta":38,"style":38},"import boto3\nimport json\nfrom datetime import datetime, timedelta\n\nbedrock = boto3.client('bedrock-runtime', region_name='eu-west-1')\ntimestream = boto3.client('timestream-query', region_name='eu-west-1')\n\ndef lambda_handler(event, context):\n    # Query last hour's data from Timestream\n    tank_id = event['tank_id']\n    query = f\"\"\"\n        SELECT\n            time,\n            measure_value::double as weight\n        FROM\n            \"FactoryData\".\"TankWeights\"\n        WHERE\n            tank_id = '{tank_id}'\n            AND time > ago(1h)\n        ORDER BY\n            time DESC\n    \"\"\"\n\n    result = timestream.query(QueryString=query)\n    weights = [float(row['Data'][1]['ScalarValue'])\n               for row in result['Rows']]\n\n    # Create prompt for Claude\n    prompt = f\"\"\"\nYou are an industrial automation expert analyzing loadcell data.\n\nTank {tank_id} weight measurements (last hour, newest first):\n{json.dumps(weights[:20], indent=2)}\n\nStatistical summary:\n- Mean: {sum(weights)/len(weights):.2f} kg\n- Min: {min(weights):.2f} kg\n- Max: {max(weights):.2f} kg\n- Std Dev: {(sum([(x-sum(weights)/len(weights))**2 for x in weights])/len(weights))**0.5:.2f} kg\n\nAnalyze this data and respond in JSON format:\n{{\n  \"anomaly_detected\": true/false,\n  \"anomaly_type\": \"sudden_drop|gradual_drift|oscillation|normal\",\n  \"severity\": \"low|medium|high|critical\",\n  \"probable_cause\": \"explanation\",\n  \"recommended_action\": \"specific action\",\n  \"confidence\": 0.0-1.0\n}}\n\"\"\"\n\n    # Call Claude 3 Haiku (cost-effective)\n    response = bedrock.invoke_model(\n        modelId='anthropic.claude-3-haiku-20240307-v1:0',\n        contentType='application/json',\n        accept='application/json',\n        body=json.dumps({\n            \"anthropic_version\": \"bedrock-2023-05-31\",\n            \"max_tokens\": 1000,\n            \"messages\": [\n                {\n                    \"role\": \"user\",\n                    \"content\": prompt\n                }\n            ]\n        })\n    )\n\n    # Parse response\n    response_body = json.loads(response['body'].read())\n    analysis = json.loads(response_body['content'][0]['text'])\n\n    # Send SNS alert if critical\n    if analysis['severity'] in ['high', 'critical']:\n        sns = boto3.client('sns')\n        sns.publish(\n            TopicArn='arn:aws:sns:eu-west-1:xxx:factory-alerts',\n            Subject=f\"Critical Anomaly: Tank {tank_id}\",\n            Message=json.dumps(analysis, indent=2)\n        )\n\n    return {\n        'statusCode': 200,\n        'body': json.dumps(analysis)\n    }\n",[36,3309,3310,3315,3320,3325,3329,3334,3339,3343,3348,3353,3358,3363,3368,3373,3379,3385,3391,3397,3403,3409,3415,3421,3427,3432,3438,3444,3450,3455,3461,3467,3473,3478,3484,3490,3495,3501,3507,3513,3519,3525,3530,3536,3542,3548,3554,3560,3566,3572,3578,3584,3590,3595,3601,3607,3613,3619,3625,3631,3637,3643,3649,3655,3661,3667,3673,3679,3685,3691,3696,3702,3708,3714,3719,3725,3731,3737,3743,3749,3755,3761,3767,3772,3778,3784,3790],{"__ignoreMap":38},[270,3311,3312],{"class":272,"line":273},[270,3313,3314],{},"import boto3\n",[270,3316,3317],{"class":272,"line":279},[270,3318,3319],{},"import json\n",[270,3321,3322],{"class":272,"line":285},[270,3323,3324],{},"from datetime import datetime, timedelta\n",[270,3326,3327],{"class":272,"line":291},[270,3328,775],{"emptyLinePlaceholder":524},[270,3330,3331],{"class":272,"line":297},[270,3332,3333],{},"bedrock = boto3.client('bedrock-runtime', region_name='eu-west-1')\n",[270,3335,3336],{"class":272,"line":303},[270,3337,3338],{},"timestream = boto3.client('timestream-query', region_name='eu-west-1')\n",[270,3340,3341],{"class":272,"line":515},[270,3342,775],{"emptyLinePlaceholder":524},[270,3344,3345],{"class":272,"line":793},[270,3346,3347],{},"def lambda_handler(event, context):\n",[270,3349,3350],{"class":272,"line":799},[270,3351,3352],{},"    # Query last hour's data from Timestream\n",[270,3354,3355],{"class":272,"line":805},[270,3356,3357],{},"    tank_id = event['tank_id']\n",[270,3359,3360],{"class":272,"line":2120},[270,3361,3362],{},"    query = f\"\"\"\n",[270,3364,3365],{"class":272,"line":2126},[270,3366,3367],{},"        SELECT\n",[270,3369,3370],{"class":272,"line":2132},[270,3371,3372],{},"            time,\n",[270,3374,3376],{"class":272,"line":3375},14,[270,3377,3378],{},"            measure_value::double as weight\n",[270,3380,3382],{"class":272,"line":3381},15,[270,3383,3384],{},"        FROM\n",[270,3386,3388],{"class":272,"line":3387},16,[270,3389,3390],{},"            \"FactoryData\".\"TankWeights\"\n",[270,3392,3394],{"class":272,"line":3393},17,[270,3395,3396],{},"        WHERE\n",[270,3398,3400],{"class":272,"line":3399},18,[270,3401,3402],{},"            tank_id = '{tank_id}'\n",[270,3404,3406],{"class":272,"line":3405},19,[270,3407,3408],{},"            AND time > ago(1h)\n",[270,3410,3412],{"class":272,"line":3411},20,[270,3413,3414],{},"        ORDER BY\n",[270,3416,3418],{"class":272,"line":3417},21,[270,3419,3420],{},"            time DESC\n",[270,3422,3424],{"class":272,"line":3423},22,[270,3425,3426],{},"    \"\"\"\n",[270,3428,3430],{"class":272,"line":3429},23,[270,3431,775],{"emptyLinePlaceholder":524},[270,3433,3435],{"class":272,"line":3434},24,[270,3436,3437],{},"    result = timestream.query(QueryString=query)\n",[270,3439,3441],{"class":272,"line":3440},25,[270,3442,3443],{},"    weights = [float(row['Data'][1]['ScalarValue'])\n",[270,3445,3447],{"class":272,"line":3446},26,[270,3448,3449],{},"               for row in result['Rows']]\n",[270,3451,3453],{"class":272,"line":3452},27,[270,3454,775],{"emptyLinePlaceholder":524},[270,3456,3458],{"class":272,"line":3457},28,[270,3459,3460],{},"    # Create prompt for Claude\n",[270,3462,3464],{"class":272,"line":3463},29,[270,3465,3466],{},"    prompt = f\"\"\"\n",[270,3468,3470],{"class":272,"line":3469},30,[270,3471,3472],{},"You are an industrial automation expert analyzing loadcell data.\n",[270,3474,3476],{"class":272,"line":3475},31,[270,3477,775],{"emptyLinePlaceholder":524},[270,3479,3481],{"class":272,"line":3480},32,[270,3482,3483],{},"Tank {tank_id} weight measurements (last hour, newest first):\n",[270,3485,3487],{"class":272,"line":3486},33,[270,3488,3489],{},"{json.dumps(weights[:20], indent=2)}\n",[270,3491,3493],{"class":272,"line":3492},34,[270,3494,775],{"emptyLinePlaceholder":524},[270,3496,3498],{"class":272,"line":3497},35,[270,3499,3500],{},"Statistical summary:\n",[270,3502,3504],{"class":272,"line":3503},36,[270,3505,3506],{},"- Mean: {sum(weights)/len(weights):.2f} kg\n",[270,3508,3510],{"class":272,"line":3509},37,[270,3511,3512],{},"- Min: {min(weights):.2f} kg\n",[270,3514,3516],{"class":272,"line":3515},38,[270,3517,3518],{},"- Max: {max(weights):.2f} kg\n",[270,3520,3522],{"class":272,"line":3521},39,[270,3523,3524],{},"- Std Dev: {(sum([(x-sum(weights)/len(weights))**2 for x in weights])/len(weights))**0.5:.2f} kg\n",[270,3526,3528],{"class":272,"line":3527},40,[270,3529,775],{"emptyLinePlaceholder":524},[270,3531,3533],{"class":272,"line":3532},41,[270,3534,3535],{},"Analyze this data and respond in JSON format:\n",[270,3537,3539],{"class":272,"line":3538},42,[270,3540,3541],{},"{{\n",[270,3543,3545],{"class":272,"line":3544},43,[270,3546,3547],{},"  \"anomaly_detected\": true/false,\n",[270,3549,3551],{"class":272,"line":3550},44,[270,3552,3553],{},"  \"anomaly_type\": \"sudden_drop|gradual_drift|oscillation|normal\",\n",[270,3555,3557],{"class":272,"line":3556},45,[270,3558,3559],{},"  \"severity\": \"low|medium|high|critical\",\n",[270,3561,3563],{"class":272,"line":3562},46,[270,3564,3565],{},"  \"probable_cause\": \"explanation\",\n",[270,3567,3569],{"class":272,"line":3568},47,[270,3570,3571],{},"  \"recommended_action\": \"specific action\",\n",[270,3573,3575],{"class":272,"line":3574},48,[270,3576,3577],{},"  \"confidence\": 0.0-1.0\n",[270,3579,3581],{"class":272,"line":3580},49,[270,3582,3583],{},"}}\n",[270,3585,3587],{"class":272,"line":3586},50,[270,3588,3589],{},"\"\"\"\n",[270,3591,3593],{"class":272,"line":3592},51,[270,3594,775],{"emptyLinePlaceholder":524},[270,3596,3598],{"class":272,"line":3597},52,[270,3599,3600],{},"    # Call Claude 3 Haiku (cost-effective)\n",[270,3602,3604],{"class":272,"line":3603},53,[270,3605,3606],{},"    response = bedrock.invoke_model(\n",[270,3608,3610],{"class":272,"line":3609},54,[270,3611,3612],{},"        modelId='anthropic.claude-3-haiku-20240307-v1:0',\n",[270,3614,3616],{"class":272,"line":3615},55,[270,3617,3618],{},"        contentType='application/json',\n",[270,3620,3622],{"class":272,"line":3621},56,[270,3623,3624],{},"        accept='application/json',\n",[270,3626,3628],{"class":272,"line":3627},57,[270,3629,3630],{},"        body=json.dumps({\n",[270,3632,3634],{"class":272,"line":3633},58,[270,3635,3636],{},"            \"anthropic_version\": \"bedrock-2023-05-31\",\n",[270,3638,3640],{"class":272,"line":3639},59,[270,3641,3642],{},"            \"max_tokens\": 1000,\n",[270,3644,3646],{"class":272,"line":3645},60,[270,3647,3648],{},"            \"messages\": [\n",[270,3650,3652],{"class":272,"line":3651},61,[270,3653,3654],{},"                {\n",[270,3656,3658],{"class":272,"line":3657},62,[270,3659,3660],{},"                    \"role\": \"user\",\n",[270,3662,3664],{"class":272,"line":3663},63,[270,3665,3666],{},"                    \"content\": prompt\n",[270,3668,3670],{"class":272,"line":3669},64,[270,3671,3672],{},"                }\n",[270,3674,3676],{"class":272,"line":3675},65,[270,3677,3678],{},"            ]\n",[270,3680,3682],{"class":272,"line":3681},66,[270,3683,3684],{},"        })\n",[270,3686,3688],{"class":272,"line":3687},67,[270,3689,3690],{},"    )\n",[270,3692,3694],{"class":272,"line":3693},68,[270,3695,775],{"emptyLinePlaceholder":524},[270,3697,3699],{"class":272,"line":3698},69,[270,3700,3701],{},"    # Parse response\n",[270,3703,3705],{"class":272,"line":3704},70,[270,3706,3707],{},"    response_body = json.loads(response['body'].read())\n",[270,3709,3711],{"class":272,"line":3710},71,[270,3712,3713],{},"    analysis = json.loads(response_body['content'][0]['text'])\n",[270,3715,3717],{"class":272,"line":3716},72,[270,3718,775],{"emptyLinePlaceholder":524},[270,3720,3722],{"class":272,"line":3721},73,[270,3723,3724],{},"    # Send SNS alert if critical\n",[270,3726,3728],{"class":272,"line":3727},74,[270,3729,3730],{},"    if analysis['severity'] in ['high', 'critical']:\n",[270,3732,3734],{"class":272,"line":3733},75,[270,3735,3736],{},"        sns = boto3.client('sns')\n",[270,3738,3740],{"class":272,"line":3739},76,[270,3741,3742],{},"        sns.publish(\n",[270,3744,3746],{"class":272,"line":3745},77,[270,3747,3748],{},"            TopicArn='arn:aws:sns:eu-west-1:xxx:factory-alerts',\n",[270,3750,3752],{"class":272,"line":3751},78,[270,3753,3754],{},"            Subject=f\"Critical Anomaly: Tank {tank_id}\",\n",[270,3756,3758],{"class":272,"line":3757},79,[270,3759,3760],{},"            Message=json.dumps(analysis, indent=2)\n",[270,3762,3764],{"class":272,"line":3763},80,[270,3765,3766],{},"        )\n",[270,3768,3770],{"class":272,"line":3769},81,[270,3771,775],{"emptyLinePlaceholder":524},[270,3773,3775],{"class":272,"line":3774},82,[270,3776,3777],{},"    return {\n",[270,3779,3781],{"class":272,"line":3780},83,[270,3782,3783],{},"        'statusCode': 200,\n",[270,3785,3787],{"class":272,"line":3786},84,[270,3788,3789],{},"        'body': json.dumps(analysis)\n",[270,3791,3793],{"class":272,"line":3792},85,[270,3794,3795],{},"    }\n",[16,3797,3798],{},[93,3799,3800],{},"Example Output:",[29,3802,3806],{"className":3803,"code":3804,"language":3805,"meta":38,"style":38},"language-json shiki shiki-themes github-light github-dark","{\n  \"anomaly_detected\": true,\n  \"anomaly_type\": \"sudden_drop\",\n  \"severity\": \"high\",\n  \"probable_cause\": \"Weight dropped 450 kg in 2 minutes, indicating possible valve opening or leak\",\n  \"recommended_action\": \"Inspect Tank 2 outlet valve and piping for leaks. Check flow meter readings.\",\n  \"confidence\": 0.89\n}\n","json",[36,3807,3808,3813,3826,3838,3850,3862,3874,3884],{"__ignoreMap":38},[270,3809,3810],{"class":272,"line":273},[270,3811,3812],{"class":1918},"{\n",[270,3814,3815,3818,3820,3823],{"class":272,"line":279},[270,3816,3817],{"class":2053},"  \"anomaly_detected\"",[270,3819,1927],{"class":1918},[270,3821,3822],{"class":2053},"true",[270,3824,3825],{"class":1918},",\n",[270,3827,3828,3831,3833,3836],{"class":272,"line":285},[270,3829,3830],{"class":2053},"  \"anomaly_type\"",[270,3832,1927],{"class":1918},[270,3834,3835],{"class":1930},"\"sudden_drop\"",[270,3837,3825],{"class":1918},[270,3839,3840,3843,3845,3848],{"class":272,"line":291},[270,3841,3842],{"class":2053},"  \"severity\"",[270,3844,1927],{"class":1918},[270,3846,3847],{"class":1930},"\"high\"",[270,3849,3825],{"class":1918},[270,3851,3852,3855,3857,3860],{"class":272,"line":297},[270,3853,3854],{"class":2053},"  \"probable_cause\"",[270,3856,1927],{"class":1918},[270,3858,3859],{"class":1930},"\"Weight dropped 450 kg in 2 minutes, indicating possible valve opening or leak\"",[270,3861,3825],{"class":1918},[270,3863,3864,3867,3869,3872],{"class":272,"line":303},[270,3865,3866],{"class":2053},"  \"recommended_action\"",[270,3868,1927],{"class":1918},[270,3870,3871],{"class":1930},"\"Inspect Tank 2 outlet valve and piping for leaks. Check flow meter readings.\"",[270,3873,3825],{"class":1918},[270,3875,3876,3879,3881],{"class":272,"line":515},[270,3877,3878],{"class":2053},"  \"confidence\"",[270,3880,1927],{"class":1918},[270,3882,3883],{"class":2053},"0.89\n",[270,3885,3886],{"class":272,"line":793},[270,3887,2129],{"class":1918},[11,3889,3891],{"id":3890},"application-2-natural-language-querying","Application 2: Natural Language Querying",[24,3893,3294],{"id":3894},"scenario-1",[16,3896,3897,3898],{},"Operations manager asks: ",[3899,3900,3901],"em",{},"\"Which tank had the highest fill rate yesterday?\"",[24,3903,3905],{"id":3904},"text-to-sql-with-claude","Text-to-SQL with Claude",[29,3907,3909],{"className":751,"code":3908,"language":753,"meta":38,"style":38},"def natural_language_to_sql(question, table_schema):\n    \"\"\"Convert natural language to Timestream SQL\"\"\"\n\n    prompt = f\"\"\"\nYou are an expert in AWS Timestream SQL. Convert the user's question to a valid SQL query.\n\nDatabase Schema:\nTable: FactoryData.TankWeights\nColumns:\n- tank_id (VARCHAR): Tank identifier (1, 2, 3, etc.)\n- time (TIMESTAMP): Measurement timestamp\n- measure_name (VARCHAR): Metric name\n- measure_value (DOUBLE): Metric value\n\nUser Question: \"{question}\"\n\nRequirements:\n1. Use Timestream-specific functions (ago(), bin(), etc.)\n2. Return only the SQL query, no explanations\n3. Use appropriate time filters\n\nSQL Query:\n\"\"\"\n\n    response = bedrock.invoke_model(\n        modelId='anthropic.claude-3-sonnet-20240229-v1:0',\n        body=json.dumps({\n            \"anthropic_version\": \"bedrock-2023-05-31\",\n            \"max_tokens\": 500,\n            \"messages\": [{\"role\": \"user\", \"content\": prompt}]\n        })\n    )\n\n    sql_query = json.loads(response['body'].read())['content'][0]['text']\n    return sql_query.strip()\n\n# Example usage\nquestion = \"Which tank had the highest fill rate yesterday?\"\nsql = natural_language_to_sql(question, schema)\n\nprint(sql)\n# Output:\n# WITH hourly_avg AS (\n#   SELECT\n#     tank_id,\n#     bin(time, 1h) as hour_bin,\n#     AVG(measure_value::double) as avg_weight\n#   FROM \"FactoryData\".\"TankWeights\"\n#   WHERE time BETWEEN ago(48h) AND ago(24h)\n#   GROUP BY tank_id, bin(time, 1h)\n# )\n# SELECT\n#   tank_id,\n#   MAX(avg_weight) - MIN(avg_weight) as total_fill\n# FROM hourly_avg\n# GROUP BY tank_id\n# ORDER BY total_fill DESC\n# LIMIT 1\n\n# Execute the generated SQL\nresult = timestream.query(QueryString=sql)\n",[36,3910,3911,3916,3921,3925,3929,3934,3938,3943,3948,3953,3958,3963,3968,3973,3977,3982,3986,3991,3996,4001,4006,4010,4015,4019,4023,4027,4032,4036,4040,4045,4050,4054,4058,4062,4067,4072,4076,4081,4086,4091,4095,4100,4105,4110,4115,4120,4125,4130,4135,4140,4145,4150,4155,4160,4165,4170,4175,4180,4185,4189,4194],{"__ignoreMap":38},[270,3912,3913],{"class":272,"line":273},[270,3914,3915],{},"def natural_language_to_sql(question, table_schema):\n",[270,3917,3918],{"class":272,"line":279},[270,3919,3920],{},"    \"\"\"Convert natural language to Timestream SQL\"\"\"\n",[270,3922,3923],{"class":272,"line":285},[270,3924,775],{"emptyLinePlaceholder":524},[270,3926,3927],{"class":272,"line":291},[270,3928,3466],{},[270,3930,3931],{"class":272,"line":297},[270,3932,3933],{},"You are an expert in AWS Timestream SQL. Convert the user's question to a valid SQL query.\n",[270,3935,3936],{"class":272,"line":303},[270,3937,775],{"emptyLinePlaceholder":524},[270,3939,3940],{"class":272,"line":515},[270,3941,3942],{},"Database Schema:\n",[270,3944,3945],{"class":272,"line":793},[270,3946,3947],{},"Table: FactoryData.TankWeights\n",[270,3949,3950],{"class":272,"line":799},[270,3951,3952],{},"Columns:\n",[270,3954,3955],{"class":272,"line":805},[270,3956,3957],{},"- tank_id (VARCHAR): Tank identifier (1, 2, 3, etc.)\n",[270,3959,3960],{"class":272,"line":2120},[270,3961,3962],{},"- time (TIMESTAMP): Measurement timestamp\n",[270,3964,3965],{"class":272,"line":2126},[270,3966,3967],{},"- measure_name (VARCHAR): Metric name\n",[270,3969,3970],{"class":272,"line":2132},[270,3971,3972],{},"- measure_value (DOUBLE): Metric value\n",[270,3974,3975],{"class":272,"line":3375},[270,3976,775],{"emptyLinePlaceholder":524},[270,3978,3979],{"class":272,"line":3381},[270,3980,3981],{},"User Question: \"{question}\"\n",[270,3983,3984],{"class":272,"line":3387},[270,3985,775],{"emptyLinePlaceholder":524},[270,3987,3988],{"class":272,"line":3393},[270,3989,3990],{},"Requirements:\n",[270,3992,3993],{"class":272,"line":3399},[270,3994,3995],{},"1. Use Timestream-specific functions (ago(), bin(), etc.)\n",[270,3997,3998],{"class":272,"line":3405},[270,3999,4000],{},"2. Return only the SQL query, no explanations\n",[270,4002,4003],{"class":272,"line":3411},[270,4004,4005],{},"3. Use appropriate time filters\n",[270,4007,4008],{"class":272,"line":3417},[270,4009,775],{"emptyLinePlaceholder":524},[270,4011,4012],{"class":272,"line":3423},[270,4013,4014],{},"SQL Query:\n",[270,4016,4017],{"class":272,"line":3429},[270,4018,3589],{},[270,4020,4021],{"class":272,"line":3434},[270,4022,775],{"emptyLinePlaceholder":524},[270,4024,4025],{"class":272,"line":3440},[270,4026,3606],{},[270,4028,4029],{"class":272,"line":3446},[270,4030,4031],{},"        modelId='anthropic.claude-3-sonnet-20240229-v1:0',\n",[270,4033,4034],{"class":272,"line":3452},[270,4035,3630],{},[270,4037,4038],{"class":272,"line":3457},[270,4039,3636],{},[270,4041,4042],{"class":272,"line":3463},[270,4043,4044],{},"            \"max_tokens\": 500,\n",[270,4046,4047],{"class":272,"line":3469},[270,4048,4049],{},"            \"messages\": [{\"role\": \"user\", \"content\": prompt}]\n",[270,4051,4052],{"class":272,"line":3475},[270,4053,3684],{},[270,4055,4056],{"class":272,"line":3480},[270,4057,3690],{},[270,4059,4060],{"class":272,"line":3486},[270,4061,775],{"emptyLinePlaceholder":524},[270,4063,4064],{"class":272,"line":3492},[270,4065,4066],{},"    sql_query = json.loads(response['body'].read())['content'][0]['text']\n",[270,4068,4069],{"class":272,"line":3497},[270,4070,4071],{},"    return sql_query.strip()\n",[270,4073,4074],{"class":272,"line":3503},[270,4075,775],{"emptyLinePlaceholder":524},[270,4077,4078],{"class":272,"line":3509},[270,4079,4080],{},"# Example usage\n",[270,4082,4083],{"class":272,"line":3515},[270,4084,4085],{},"question = \"Which tank had the highest fill rate yesterday?\"\n",[270,4087,4088],{"class":272,"line":3521},[270,4089,4090],{},"sql = natural_language_to_sql(question, schema)\n",[270,4092,4093],{"class":272,"line":3527},[270,4094,775],{"emptyLinePlaceholder":524},[270,4096,4097],{"class":272,"line":3532},[270,4098,4099],{},"print(sql)\n",[270,4101,4102],{"class":272,"line":3538},[270,4103,4104],{},"# Output:\n",[270,4106,4107],{"class":272,"line":3544},[270,4108,4109],{},"# WITH hourly_avg AS (\n",[270,4111,4112],{"class":272,"line":3550},[270,4113,4114],{},"#   SELECT\n",[270,4116,4117],{"class":272,"line":3556},[270,4118,4119],{},"#     tank_id,\n",[270,4121,4122],{"class":272,"line":3562},[270,4123,4124],{},"#     bin(time, 1h) as hour_bin,\n",[270,4126,4127],{"class":272,"line":3568},[270,4128,4129],{},"#     AVG(measure_value::double) as avg_weight\n",[270,4131,4132],{"class":272,"line":3574},[270,4133,4134],{},"#   FROM \"FactoryData\".\"TankWeights\"\n",[270,4136,4137],{"class":272,"line":3580},[270,4138,4139],{},"#   WHERE time BETWEEN ago(48h) AND ago(24h)\n",[270,4141,4142],{"class":272,"line":3586},[270,4143,4144],{},"#   GROUP BY tank_id, bin(time, 1h)\n",[270,4146,4147],{"class":272,"line":3592},[270,4148,4149],{},"# )\n",[270,4151,4152],{"class":272,"line":3597},[270,4153,4154],{},"# SELECT\n",[270,4156,4157],{"class":272,"line":3603},[270,4158,4159],{},"#   tank_id,\n",[270,4161,4162],{"class":272,"line":3609},[270,4163,4164],{},"#   MAX(avg_weight) - MIN(avg_weight) as total_fill\n",[270,4166,4167],{"class":272,"line":3615},[270,4168,4169],{},"# FROM hourly_avg\n",[270,4171,4172],{"class":272,"line":3621},[270,4173,4174],{},"# GROUP BY tank_id\n",[270,4176,4177],{"class":272,"line":3627},[270,4178,4179],{},"# ORDER BY total_fill DESC\n",[270,4181,4182],{"class":272,"line":3633},[270,4183,4184],{},"# LIMIT 1\n",[270,4186,4187],{"class":272,"line":3639},[270,4188,775],{"emptyLinePlaceholder":524},[270,4190,4191],{"class":272,"line":3645},[270,4192,4193],{},"# Execute the generated SQL\n",[270,4195,4196],{"class":272,"line":3651},[270,4197,4198],{},"result = timestream.query(QueryString=sql)\n",[11,4200,4202],{"id":4201},"application-3-automated-maintenance-reports","Application 3: Automated Maintenance Reports",[24,4204,3294],{"id":4205},"scenario-2",[16,4207,4208],{},"Generate weekly maintenance report summarizing all tanks' status.",[24,4210,4212],{"id":4211},"report-generation-with-claude","Report Generation with Claude",[29,4214,4216],{"className":751,"code":4215,"language":753,"meta":38,"style":38},"def generate_maintenance_report(start_date, end_date):\n    \"\"\"Generate comprehensive weekly report\"\"\"\n\n    # Collect data from multiple sources\n    tank_data = get_tank_statistics(start_date, end_date)\n    alarms = get_alarm_history(start_date, end_date)\n    calibrations = get_calibration_log(start_date, end_date)\n\n    prompt = f\"\"\"\nGenerate a professional weekly maintenance report for a milk processing facility.\n\nData Summary:\n{json.dumps(tank_data, indent=2)}\n\nAlarms:\n{json.dumps(alarms, indent=2)}\n\nCalibrations:\n{json.dumps(calibrations, indent=2)}\n\nReport Structure:\n1. Executive Summary\n2. Tank-by-Tank Status\n3. Anomalies and Alarms\n4. Maintenance Activities\n5. Recommendations for Next Week\n\nFormat as HTML for email distribution.\n\"\"\"\n\n    response = bedrock.invoke_model(\n        modelId='anthropic.claude-3-sonnet-20240229-v1:0',\n        body=json.dumps({\n            \"anthropic_version\": \"bedrock-2023-05-31\",\n            \"max_tokens\": 4000,\n            \"messages\": [{\"role\": \"user\", \"content\": prompt}]\n        })\n    )\n\n    report_html = json.loads(response['body'].read())['content'][0]['text']\n\n    # Save to S3\n    s3 = boto3.client('s3')\n    s3.put_object(\n        Bucket='factory-reports',\n        Key=f'maintenance/weekly_{start_date}.html',\n        Body=report_html,\n        ContentType='text/html'\n    )\n\n    # Email report\n    ses = boto3.client('ses')\n    ses.send_email(\n        Source='reports@factory.com',\n        Destination={'ToAddresses': ['maintenance@factory.com']},\n        Message={\n            'Subject': {'Data': f'Weekly Report: {start_date}'},\n            'Body': {'Html': {'Data': report_html}}\n        }\n    )\n\n    return report_html\n",[36,4217,4218,4223,4228,4232,4237,4242,4247,4252,4256,4260,4265,4269,4274,4279,4283,4288,4293,4297,4302,4307,4311,4316,4321,4326,4331,4336,4341,4345,4350,4354,4358,4362,4366,4370,4374,4379,4383,4387,4391,4395,4400,4404,4409,4414,4419,4424,4429,4434,4439,4443,4447,4452,4457,4462,4467,4472,4477,4482,4487,4492,4496,4500],{"__ignoreMap":38},[270,4219,4220],{"class":272,"line":273},[270,4221,4222],{},"def generate_maintenance_report(start_date, end_date):\n",[270,4224,4225],{"class":272,"line":279},[270,4226,4227],{},"    \"\"\"Generate comprehensive weekly report\"\"\"\n",[270,4229,4230],{"class":272,"line":285},[270,4231,775],{"emptyLinePlaceholder":524},[270,4233,4234],{"class":272,"line":291},[270,4235,4236],{},"    # Collect data from multiple sources\n",[270,4238,4239],{"class":272,"line":297},[270,4240,4241],{},"    tank_data = get_tank_statistics(start_date, end_date)\n",[270,4243,4244],{"class":272,"line":303},[270,4245,4246],{},"    alarms = get_alarm_history(start_date, end_date)\n",[270,4248,4249],{"class":272,"line":515},[270,4250,4251],{},"    calibrations = get_calibration_log(start_date, end_date)\n",[270,4253,4254],{"class":272,"line":793},[270,4255,775],{"emptyLinePlaceholder":524},[270,4257,4258],{"class":272,"line":799},[270,4259,3466],{},[270,4261,4262],{"class":272,"line":805},[270,4263,4264],{},"Generate a professional weekly maintenance report for a milk processing facility.\n",[270,4266,4267],{"class":272,"line":2120},[270,4268,775],{"emptyLinePlaceholder":524},[270,4270,4271],{"class":272,"line":2126},[270,4272,4273],{},"Data Summary:\n",[270,4275,4276],{"class":272,"line":2132},[270,4277,4278],{},"{json.dumps(tank_data, indent=2)}\n",[270,4280,4281],{"class":272,"line":3375},[270,4282,775],{"emptyLinePlaceholder":524},[270,4284,4285],{"class":272,"line":3381},[270,4286,4287],{},"Alarms:\n",[270,4289,4290],{"class":272,"line":3387},[270,4291,4292],{},"{json.dumps(alarms, indent=2)}\n",[270,4294,4295],{"class":272,"line":3393},[270,4296,775],{"emptyLinePlaceholder":524},[270,4298,4299],{"class":272,"line":3399},[270,4300,4301],{},"Calibrations:\n",[270,4303,4304],{"class":272,"line":3405},[270,4305,4306],{},"{json.dumps(calibrations, indent=2)}\n",[270,4308,4309],{"class":272,"line":3411},[270,4310,775],{"emptyLinePlaceholder":524},[270,4312,4313],{"class":272,"line":3417},[270,4314,4315],{},"Report Structure:\n",[270,4317,4318],{"class":272,"line":3423},[270,4319,4320],{},"1. Executive Summary\n",[270,4322,4323],{"class":272,"line":3429},[270,4324,4325],{},"2. Tank-by-Tank Status\n",[270,4327,4328],{"class":272,"line":3434},[270,4329,4330],{},"3. Anomalies and Alarms\n",[270,4332,4333],{"class":272,"line":3440},[270,4334,4335],{},"4. Maintenance Activities\n",[270,4337,4338],{"class":272,"line":3446},[270,4339,4340],{},"5. Recommendations for Next Week\n",[270,4342,4343],{"class":272,"line":3452},[270,4344,775],{"emptyLinePlaceholder":524},[270,4346,4347],{"class":272,"line":3457},[270,4348,4349],{},"Format as HTML for email distribution.\n",[270,4351,4352],{"class":272,"line":3463},[270,4353,3589],{},[270,4355,4356],{"class":272,"line":3469},[270,4357,775],{"emptyLinePlaceholder":524},[270,4359,4360],{"class":272,"line":3475},[270,4361,3606],{},[270,4363,4364],{"class":272,"line":3480},[270,4365,4031],{},[270,4367,4368],{"class":272,"line":3486},[270,4369,3630],{},[270,4371,4372],{"class":272,"line":3492},[270,4373,3636],{},[270,4375,4376],{"class":272,"line":3497},[270,4377,4378],{},"            \"max_tokens\": 4000,\n",[270,4380,4381],{"class":272,"line":3503},[270,4382,4049],{},[270,4384,4385],{"class":272,"line":3509},[270,4386,3684],{},[270,4388,4389],{"class":272,"line":3515},[270,4390,3690],{},[270,4392,4393],{"class":272,"line":3521},[270,4394,775],{"emptyLinePlaceholder":524},[270,4396,4397],{"class":272,"line":3527},[270,4398,4399],{},"    report_html = json.loads(response['body'].read())['content'][0]['text']\n",[270,4401,4402],{"class":272,"line":3532},[270,4403,775],{"emptyLinePlaceholder":524},[270,4405,4406],{"class":272,"line":3538},[270,4407,4408],{},"    # Save to S3\n",[270,4410,4411],{"class":272,"line":3544},[270,4412,4413],{},"    s3 = boto3.client('s3')\n",[270,4415,4416],{"class":272,"line":3550},[270,4417,4418],{},"    s3.put_object(\n",[270,4420,4421],{"class":272,"line":3556},[270,4422,4423],{},"        Bucket='factory-reports',\n",[270,4425,4426],{"class":272,"line":3562},[270,4427,4428],{},"        Key=f'maintenance/weekly_{start_date}.html',\n",[270,4430,4431],{"class":272,"line":3568},[270,4432,4433],{},"        Body=report_html,\n",[270,4435,4436],{"class":272,"line":3574},[270,4437,4438],{},"        ContentType='text/html'\n",[270,4440,4441],{"class":272,"line":3580},[270,4442,3690],{},[270,4444,4445],{"class":272,"line":3586},[270,4446,775],{"emptyLinePlaceholder":524},[270,4448,4449],{"class":272,"line":3592},[270,4450,4451],{},"    # Email report\n",[270,4453,4454],{"class":272,"line":3597},[270,4455,4456],{},"    ses = boto3.client('ses')\n",[270,4458,4459],{"class":272,"line":3603},[270,4460,4461],{},"    ses.send_email(\n",[270,4463,4464],{"class":272,"line":3609},[270,4465,4466],{},"        Source='reports@factory.com',\n",[270,4468,4469],{"class":272,"line":3615},[270,4470,4471],{},"        Destination={'ToAddresses': ['maintenance@factory.com']},\n",[270,4473,4474],{"class":272,"line":3621},[270,4475,4476],{},"        Message={\n",[270,4478,4479],{"class":272,"line":3627},[270,4480,4481],{},"            'Subject': {'Data': f'Weekly Report: {start_date}'},\n",[270,4483,4484],{"class":272,"line":3633},[270,4485,4486],{},"            'Body': {'Html': {'Data': report_html}}\n",[270,4488,4489],{"class":272,"line":3639},[270,4490,4491],{},"        }\n",[270,4493,4494],{"class":272,"line":3645},[270,4495,3690],{},[270,4497,4498],{"class":272,"line":3651},[270,4499,775],{"emptyLinePlaceholder":524},[270,4501,4502],{"class":272,"line":3657},[270,4503,4504],{},"    return report_html\n",[11,4506,4508],{"id":4507},"application-4-rag-for-operation-manuals","Application 4: RAG for Operation Manuals",[24,4510,4512],{"id":4511},"retrieval-augmented-generation-rag","Retrieval Augmented Generation (RAG)",[16,4514,4515,4516,4519],{},"Use ",[93,4517,4518],{},"Knowledge Bases for Amazon Bedrock"," to create a chatbot answering questions from operation manuals.",[29,4521,4523],{"className":751,"code":4522,"language":753,"meta":38,"style":38},"def setup_knowledge_base():\n    \"\"\"Create knowledge base from PDF manuals\"\"\"\n\n    bedrock_agent = boto3.client('bedrock-agent')\n\n    # Create knowledge base\n    kb_response = bedrock_agent.create_knowledge_base(\n        name='FactoryOperationManuals',\n        roleArn='arn:aws:iam::xxx:role/BedrockKBRole',\n        knowledgeBaseConfiguration={\n            'type': 'VECTOR',\n            'vectorKnowledgeBaseConfiguration': {\n                'embeddingModelArn': 'arn:aws:bedrock:eu-west-1::foundation-model/amazon.titan-embed-text-v1'\n            }\n        },\n        storageConfiguration={\n            'type': 'OPENSEARCH_SERVERLESS',\n            'opensearchServerlessConfiguration': {\n                'collectionArn': 'arn:aws:aoss:eu-west-1:xxx:collection/factory-kb',\n                'vectorIndexName': 'factory-docs',\n                'fieldMapping': {\n                    'vectorField': 'vector',\n                    'textField': 'text',\n                    'metadataField': 'metadata'\n                }\n            }\n        }\n    )\n\n    kb_id = kb_response['knowledgeBase']['knowledgeBaseId']\n\n    # Add data source (S3 bucket with PDFs)\n    bedrock_agent.create_data_source(\n        knowledgeBaseId=kb_id,\n        name='OperationManualsPDF',\n        dataSourceConfiguration={\n            'type': 'S3',\n            's3Configuration': {\n                'bucketArn': 'arn:aws:s3:::factory-manuals'\n            }\n        }\n    )\n\n    return kb_id\n\ndef query_knowledge_base(kb_id, question):\n    \"\"\"Query operation manuals\"\"\"\n\n    bedrock_agent_runtime = boto3.client('bedrock-agent-runtime')\n\n    response = bedrock_agent_runtime.retrieve_and_generate(\n        input={'text': question},\n        retrieveAndGenerateConfiguration={\n            'type': 'KNOWLEDGE_BASE',\n            'knowledgeBaseConfiguration': {\n                'knowledgeBaseId': kb_id,\n                'modelArn': 'arn:aws:bedrock:eu-west-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0'\n            }\n        }\n    )\n\n    answer = response['output']['text']\n    sources = response['citations']\n\n    return answer, sources\n\n# Example\nanswer, sources = query_knowledge_base(\n    kb_id='ABCD1234',\n    question='How do I calibrate the GDT-410M loadcell transmitter?'\n)\n\nprint(answer)\n# \"To calibrate the GDT-410M: 1) Enter calibration mode by pressing...\"\n# Sources: [GDT_Manual_v2.3.pdf, page 45-47]\n",[36,4524,4525,4530,4535,4539,4544,4548,4553,4558,4563,4568,4573,4578,4583,4588,4593,4598,4603,4608,4613,4618,4623,4628,4633,4638,4643,4647,4651,4655,4659,4663,4668,4672,4677,4682,4687,4692,4697,4702,4707,4712,4716,4720,4724,4728,4733,4737,4742,4747,4751,4756,4760,4765,4770,4775,4780,4785,4790,4795,4799,4803,4807,4811,4816,4821,4825,4830,4834,4839,4844,4849,4854,4859,4863,4868,4873],{"__ignoreMap":38},[270,4526,4527],{"class":272,"line":273},[270,4528,4529],{},"def setup_knowledge_base():\n",[270,4531,4532],{"class":272,"line":279},[270,4533,4534],{},"    \"\"\"Create knowledge base from PDF manuals\"\"\"\n",[270,4536,4537],{"class":272,"line":285},[270,4538,775],{"emptyLinePlaceholder":524},[270,4540,4541],{"class":272,"line":291},[270,4542,4543],{},"    bedrock_agent = boto3.client('bedrock-agent')\n",[270,4545,4546],{"class":272,"line":297},[270,4547,775],{"emptyLinePlaceholder":524},[270,4549,4550],{"class":272,"line":303},[270,4551,4552],{},"    # Create knowledge base\n",[270,4554,4555],{"class":272,"line":515},[270,4556,4557],{},"    kb_response = bedrock_agent.create_knowledge_base(\n",[270,4559,4560],{"class":272,"line":793},[270,4561,4562],{},"        name='FactoryOperationManuals',\n",[270,4564,4565],{"class":272,"line":799},[270,4566,4567],{},"        roleArn='arn:aws:iam::xxx:role/BedrockKBRole',\n",[270,4569,4570],{"class":272,"line":805},[270,4571,4572],{},"        knowledgeBaseConfiguration={\n",[270,4574,4575],{"class":272,"line":2120},[270,4576,4577],{},"            'type': 'VECTOR',\n",[270,4579,4580],{"class":272,"line":2126},[270,4581,4582],{},"            'vectorKnowledgeBaseConfiguration': {\n",[270,4584,4585],{"class":272,"line":2132},[270,4586,4587],{},"                'embeddingModelArn': 'arn:aws:bedrock:eu-west-1::foundation-model/amazon.titan-embed-text-v1'\n",[270,4589,4590],{"class":272,"line":3375},[270,4591,4592],{},"            }\n",[270,4594,4595],{"class":272,"line":3381},[270,4596,4597],{},"        },\n",[270,4599,4600],{"class":272,"line":3387},[270,4601,4602],{},"        storageConfiguration={\n",[270,4604,4605],{"class":272,"line":3393},[270,4606,4607],{},"            'type': 'OPENSEARCH_SERVERLESS',\n",[270,4609,4610],{"class":272,"line":3399},[270,4611,4612],{},"            'opensearchServerlessConfiguration': {\n",[270,4614,4615],{"class":272,"line":3405},[270,4616,4617],{},"                'collectionArn': 'arn:aws:aoss:eu-west-1:xxx:collection/factory-kb',\n",[270,4619,4620],{"class":272,"line":3411},[270,4621,4622],{},"                'vectorIndexName': 'factory-docs',\n",[270,4624,4625],{"class":272,"line":3417},[270,4626,4627],{},"                'fieldMapping': {\n",[270,4629,4630],{"class":272,"line":3423},[270,4631,4632],{},"                    'vectorField': 'vector',\n",[270,4634,4635],{"class":272,"line":3429},[270,4636,4637],{},"                    'textField': 'text',\n",[270,4639,4640],{"class":272,"line":3434},[270,4641,4642],{},"                    'metadataField': 'metadata'\n",[270,4644,4645],{"class":272,"line":3440},[270,4646,3672],{},[270,4648,4649],{"class":272,"line":3446},[270,4650,4592],{},[270,4652,4653],{"class":272,"line":3452},[270,4654,4491],{},[270,4656,4657],{"class":272,"line":3457},[270,4658,3690],{},[270,4660,4661],{"class":272,"line":3463},[270,4662,775],{"emptyLinePlaceholder":524},[270,4664,4665],{"class":272,"line":3469},[270,4666,4667],{},"    kb_id = kb_response['knowledgeBase']['knowledgeBaseId']\n",[270,4669,4670],{"class":272,"line":3475},[270,4671,775],{"emptyLinePlaceholder":524},[270,4673,4674],{"class":272,"line":3480},[270,4675,4676],{},"    # Add data source (S3 bucket with PDFs)\n",[270,4678,4679],{"class":272,"line":3486},[270,4680,4681],{},"    bedrock_agent.create_data_source(\n",[270,4683,4684],{"class":272,"line":3492},[270,4685,4686],{},"        knowledgeBaseId=kb_id,\n",[270,4688,4689],{"class":272,"line":3497},[270,4690,4691],{},"        name='OperationManualsPDF',\n",[270,4693,4694],{"class":272,"line":3503},[270,4695,4696],{},"        dataSourceConfiguration={\n",[270,4698,4699],{"class":272,"line":3509},[270,4700,4701],{},"            'type': 'S3',\n",[270,4703,4704],{"class":272,"line":3515},[270,4705,4706],{},"            's3Configuration': {\n",[270,4708,4709],{"class":272,"line":3521},[270,4710,4711],{},"                'bucketArn': 'arn:aws:s3:::factory-manuals'\n",[270,4713,4714],{"class":272,"line":3527},[270,4715,4592],{},[270,4717,4718],{"class":272,"line":3532},[270,4719,4491],{},[270,4721,4722],{"class":272,"line":3538},[270,4723,3690],{},[270,4725,4726],{"class":272,"line":3544},[270,4727,775],{"emptyLinePlaceholder":524},[270,4729,4730],{"class":272,"line":3550},[270,4731,4732],{},"    return kb_id\n",[270,4734,4735],{"class":272,"line":3556},[270,4736,775],{"emptyLinePlaceholder":524},[270,4738,4739],{"class":272,"line":3562},[270,4740,4741],{},"def query_knowledge_base(kb_id, question):\n",[270,4743,4744],{"class":272,"line":3568},[270,4745,4746],{},"    \"\"\"Query operation manuals\"\"\"\n",[270,4748,4749],{"class":272,"line":3574},[270,4750,775],{"emptyLinePlaceholder":524},[270,4752,4753],{"class":272,"line":3580},[270,4754,4755],{},"    bedrock_agent_runtime = boto3.client('bedrock-agent-runtime')\n",[270,4757,4758],{"class":272,"line":3586},[270,4759,775],{"emptyLinePlaceholder":524},[270,4761,4762],{"class":272,"line":3592},[270,4763,4764],{},"    response = bedrock_agent_runtime.retrieve_and_generate(\n",[270,4766,4767],{"class":272,"line":3597},[270,4768,4769],{},"        input={'text': question},\n",[270,4771,4772],{"class":272,"line":3603},[270,4773,4774],{},"        retrieveAndGenerateConfiguration={\n",[270,4776,4777],{"class":272,"line":3609},[270,4778,4779],{},"            'type': 'KNOWLEDGE_BASE',\n",[270,4781,4782],{"class":272,"line":3615},[270,4783,4784],{},"            'knowledgeBaseConfiguration': {\n",[270,4786,4787],{"class":272,"line":3621},[270,4788,4789],{},"                'knowledgeBaseId': kb_id,\n",[270,4791,4792],{"class":272,"line":3627},[270,4793,4794],{},"                'modelArn': 'arn:aws:bedrock:eu-west-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0'\n",[270,4796,4797],{"class":272,"line":3633},[270,4798,4592],{},[270,4800,4801],{"class":272,"line":3639},[270,4802,4491],{},[270,4804,4805],{"class":272,"line":3645},[270,4806,3690],{},[270,4808,4809],{"class":272,"line":3651},[270,4810,775],{"emptyLinePlaceholder":524},[270,4812,4813],{"class":272,"line":3657},[270,4814,4815],{},"    answer = response['output']['text']\n",[270,4817,4818],{"class":272,"line":3663},[270,4819,4820],{},"    sources = response['citations']\n",[270,4822,4823],{"class":272,"line":3669},[270,4824,775],{"emptyLinePlaceholder":524},[270,4826,4827],{"class":272,"line":3675},[270,4828,4829],{},"    return answer, sources\n",[270,4831,4832],{"class":272,"line":3681},[270,4833,775],{"emptyLinePlaceholder":524},[270,4835,4836],{"class":272,"line":3687},[270,4837,4838],{},"# Example\n",[270,4840,4841],{"class":272,"line":3693},[270,4842,4843],{},"answer, sources = query_knowledge_base(\n",[270,4845,4846],{"class":272,"line":3698},[270,4847,4848],{},"    kb_id='ABCD1234',\n",[270,4850,4851],{"class":272,"line":3704},[270,4852,4853],{},"    question='How do I calibrate the GDT-410M loadcell transmitter?'\n",[270,4855,4856],{"class":272,"line":3710},[270,4857,4858],{},")\n",[270,4860,4861],{"class":272,"line":3716},[270,4862,775],{"emptyLinePlaceholder":524},[270,4864,4865],{"class":272,"line":3721},[270,4866,4867],{},"print(answer)\n",[270,4869,4870],{"class":272,"line":3727},[270,4871,4872],{},"# \"To calibrate the GDT-410M: 1) Enter calibration mode by pressing...\"\n",[270,4874,4875],{"class":272,"line":3733},[270,4876,4877],{},"# Sources: [GDT_Manual_v2.3.pdf, page 45-47]\n",[11,4879,4881],{"id":4880},"cost-optimization","Cost Optimization",[24,4883,4885],{"id":4884},"pricing-claude-3-models","Pricing (Claude 3 Models)",[636,4887,4888,4903],{},[639,4889,4890],{},[642,4891,4892,4894,4897,4900],{},[645,4893,3072],{},[645,4895,4896],{},"Input",[645,4898,4899],{},"Output",[645,4901,4902],{},"Use Case",[655,4904,4905,4920,4935],{},[642,4906,4907,4911,4914,4917],{},[660,4908,4909],{},[93,4910,3090],{},[660,4912,4913],{},"$0.003/1K tokens",[660,4915,4916],{},"$0.015/1K tokens",[660,4918,4919],{},"Complex analysis",[642,4921,4922,4926,4929,4932],{},[660,4923,4924],{},[93,4925,3106],{},[660,4927,4928],{},"$0.00025/1K tokens",[660,4930,4931],{},"$0.00125/1K tokens",[660,4933,4934],{},"Fast, simple tasks",[642,4936,4937,4942,4944,4947],{},[660,4938,4939],{},[93,4940,4941],{},"Claude 3 Opus",[660,4943,4916],{},[660,4945,4946],{},"$0.075/1K tokens",[660,4948,4949],{},"Most advanced",[24,4951,4953],{"id":4952},"cost-example","Cost Example",[16,4955,4956,4959],{},[93,4957,4958],{},"Scenario:"," Hourly anomaly detection for 10 tanks",[40,4961,4962,4965,4968],{},[43,4963,4964],{},"Prompt: ~500 tokens (data + instructions)",[43,4966,4967],{},"Response: ~200 tokens (JSON)",[43,4969,4970],{},"Total: 700 tokens/check",[16,4972,4973],{},[93,4974,4975],{},"Monthly Cost:",[29,4977,4980],{"className":4978,"code":4979,"language":34},[32],"10 tanks × 24 checks/day × 30 days = 7,200 checks\n7,200 × 700 tokens = 5,040,000 tokens (~5M)\n\nUsing Claude 3 Haiku:\nInput:  5M × 0.5 = 2.5M tokens × $0.00025 = $0.625\nOutput: 5M × 0.2 = 1.0M tokens × $0.00125 = $1.250\nTOTAL: ~$1.90/month\n",[36,4981,4979],{"__ignoreMap":38},[16,4983,4984,4987],{},[93,4985,4986],{},"Compare to hiring data scientist:"," $5,000+/month",[11,4989,4991],{"id":4990},"guardrails-for-safety","Guardrails for Safety",[24,4993,4995],{"id":4994},"prevent-harmful-outputs","Prevent Harmful Outputs",[29,4997,4999],{"className":751,"code":4998,"language":753,"meta":38,"style":38},"bedrock_config = {\n    \"guardrailIdentifier\": \"factory-ai-guardrails\",\n    \"guardrailVersion\": \"1\",\n    \"trace\": \"enabled\"\n}\n\nresponse = bedrock.invoke_model(\n    modelId='anthropic.claude-3-sonnet-20240229-v1:0',\n    body=json.dumps({\n        \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n        **bedrock_config\n    })\n)\n",[36,5000,5001,5006,5011,5016,5021,5025,5029,5034,5039,5044,5049,5054,5059],{"__ignoreMap":38},[270,5002,5003],{"class":272,"line":273},[270,5004,5005],{},"bedrock_config = {\n",[270,5007,5008],{"class":272,"line":279},[270,5009,5010],{},"    \"guardrailIdentifier\": \"factory-ai-guardrails\",\n",[270,5012,5013],{"class":272,"line":285},[270,5014,5015],{},"    \"guardrailVersion\": \"1\",\n",[270,5017,5018],{"class":272,"line":291},[270,5019,5020],{},"    \"trace\": \"enabled\"\n",[270,5022,5023],{"class":272,"line":297},[270,5024,2129],{},[270,5026,5027],{"class":272,"line":303},[270,5028,775],{"emptyLinePlaceholder":524},[270,5030,5031],{"class":272,"line":515},[270,5032,5033],{},"response = bedrock.invoke_model(\n",[270,5035,5036],{"class":272,"line":793},[270,5037,5038],{},"    modelId='anthropic.claude-3-sonnet-20240229-v1:0',\n",[270,5040,5041],{"class":272,"line":799},[270,5042,5043],{},"    body=json.dumps({\n",[270,5045,5046],{"class":272,"line":805},[270,5047,5048],{},"        \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n",[270,5050,5051],{"class":272,"line":2120},[270,5052,5053],{},"        **bedrock_config\n",[270,5055,5056],{"class":272,"line":2126},[270,5057,5058],{},"    })\n",[270,5060,5061],{"class":272,"line":2132},[270,5062,4858],{},[16,5064,5065],{},[93,5066,5067],{},"Guardrail Rules:",[40,5069,5070,5073,5076,5079],{},[43,5071,5072],{},"Block PII data in responses",[43,5074,5075],{},"Filter toxic content",[43,5077,5078],{},"Enforce output format (JSON only)",[43,5080,5081],{},"Content filtering for accuracy",[11,5083,444],{"id":443},[16,5085,5086,5088],{},[93,5087,3041],{}," brings enterprise-grade AI to industrial applications without ML expertise:",[16,5090,5091,5092,5095,5096,5098,5099,5102,5103,5098,5105,5108,5109,5098,5111,5114],{},"✅ ",[93,5093,5094],{},"Anomaly detection"," without model training",[2353,5097],{},"\n✅ ",[93,5100,5101],{},"Natural language SQL"," for business users",[2353,5104],{},[93,5106,5107],{},"Automated reporting"," saving hours of manual work",[2353,5110],{},[93,5112,5113],{},"RAG chatbots"," for instant manual lookups",[16,5116,5117,5118,5120],{},"Cost-effective with models like ",[93,5119,3106],{}," (~$2/month for 10 devices).",[16,5122,5123,5124,5128],{},"For data privacy-sensitive applications, consider our ",[463,5125,5127],{"href":5126},"/en/blog/on-premise-ai-solutions-with-ollama","On-Premise AI with Ollama"," solution.",[24,5130,5132],{"id":5131},"related-resources","Related Resources",[40,5134,5135,5140,5144,5149],{},[43,5136,5137],{},[463,5138,5139],{"href":5126},"On-Premise AI Solutions with Ollama",[43,5141,5142],{},[463,5143,2382],{"href":2340},[43,5145,5146],{},[463,5147,5148],{"href":1758},"Time Series Data Management with Timestream",[43,5150,5151],{},[463,5152,2983],{"href":2634},[477,5154,5155],{},"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":38,"searchDepth":279,"depth":279,"links":5157},[5158,5159,5163,5164,5168,5172,5176,5179,5183,5186],{"id":13,"depth":279,"text":14},{"id":3053,"depth":279,"text":3054,"children":5160},[5161,5162],{"id":3062,"depth":285,"text":3063},{"id":3165,"depth":285,"text":3166},{"id":3279,"depth":279,"text":3280},{"id":3289,"depth":279,"text":3290,"children":5165},[5166,5167],{"id":3293,"depth":285,"text":3294},{"id":3303,"depth":285,"text":3304},{"id":3890,"depth":279,"text":3891,"children":5169},[5170,5171],{"id":3894,"depth":285,"text":3294},{"id":3904,"depth":285,"text":3905},{"id":4201,"depth":279,"text":4202,"children":5173},[5174,5175],{"id":4205,"depth":285,"text":3294},{"id":4211,"depth":285,"text":4212},{"id":4507,"depth":279,"text":4508,"children":5177},[5178],{"id":4511,"depth":285,"text":4512},{"id":4880,"depth":279,"text":4881,"children":5180},[5181,5182],{"id":4884,"depth":285,"text":4885},{"id":4952,"depth":285,"text":4953},{"id":4990,"depth":279,"text":4991,"children":5184},[5185],{"id":4994,"depth":285,"text":4995},{"id":443,"depth":279,"text":444,"children":5187},[5188],{"id":5131,"depth":285,"text":5132},"Leveraging foundation models (Claude, Llama, Titan) for industrial applications: Anomaly detection, natural language querying, automated maintenance reports.",{"date":3011,"author":514,"readTime":805,"tags":5191},[3041,3033,5192,5193,5194,5195,5196],"Claude","Llama","Industrial AI","Foundation Models","LLM","/en/blog/aws-bedrock-industrial-generative-ai",{"title":3024,"description":5189},"en/blog/aws-bedrock-industrial-generative-ai","humil45aPfBKklHG0uussEnV7CilkPCZhAF3yAAe528",{"id":5202,"title":5203,"body":5204,"description":6152,"extension":511,"meta":6153,"navigation":524,"path":6156,"seo":6157,"stem":6158,"__hash__":6159},"en_blog/en/blog/embedded-linux-hmi-development-yocto-qt.md","Embedded Linux HMI Development: Custom Interface Design with Yocto and Qt",{"type":8,"value":5205,"toc":6128},[5206,5208,5231,5239,5243,5247,5252,5263,5268,5279,5284,5295,5299,5334,5338,5342,5349,5369,5373,5379,5383,5511,5515,5519,5597,5603,5607,5613,5618,5956,5960,5962,5968,5972,5978,5982,5992,6020,6025,6078,6080,6090,6102,6104,6126],[11,5207,14],{"id":13},[16,5209,5210,5211,467,5214,5217,5218,5220,5221,5223,5224,5227,5228,472],{},"The dominance of ",[93,5212,5213],{},"Windows CE",[93,5215,5216],{},"proprietary"," solutions in industrial HMI systems has been rapidly shifting towards ",[93,5219,2820],{}," in recent years. Our ",[463,5222,2465],{"href":2464}," are at the center of this paradigm shift: customized Linux distribution with ",[93,5225,5226],{},"Yocto Project"," and modern interface development with ",[93,5229,5230],{},"Qt/QML",[16,5232,5233,5234,5238],{},"In this article, we examine how to build an embedded Linux HMI from scratch, Qt integration on the ",[463,5235,5237],{"href":5236},"/en/blog/embedded-linux-with-yocto","Yocto infrastructure we explained in our blog",", and real-world applications.",[11,5240,5242],{"id":5241},"why-embedded-linux-qt","Why Embedded Linux + Qt?",[24,5244,5246],{"id":5245},"limitations-of-traditional-hmi-solutions","Limitations of Traditional HMI Solutions",[16,5248,5249],{},[93,5250,5251],{},"1. Windows CE / Windows Embedded",[40,5253,5254,5257,5260],{},[43,5255,5256],{},"License costs ($100+ per device)",[43,5258,5259],{},"Security updates ended (Windows CE EOL in 2018)",[43,5261,5262],{},"High hardware requirements (minimum 512MB RAM)",[16,5264,5265],{},[93,5266,5267],{},"2. Proprietary Solutions (Siemens WinCC, Rockwell FactoryTalk)",[40,5269,5270,5273,5276],{},[43,5271,5272],{},"Vendor lock-in",[43,5274,5275],{},"Limited customization options",[43,5277,5278],{},"High software costs",[16,5280,5281],{},[93,5282,5283],{},"3. Arduino/MCU-based Simple Displays",[40,5285,5286,5289,5292],{},[43,5287,5288],{},"Low graphics performance",[43,5290,5291],{},"Limited networking (weak TCP/IP stack)",[43,5293,5294],{},"Insufficient for complex applications",[24,5296,5298],{"id":5297},"advantages-of-embedded-linux-qt","Advantages of Embedded Linux + Qt",[16,5300,5091,5301,5304,5305,5098,5307,5310,5311,5098,5313,5316,5317,5098,5319,5322,5323,5098,5325,5327,5328,5098,5330,5333],{},[93,5302,5303],{},"Open Source & Free",": No license costs",[2353,5306],{},[93,5308,5309],{},"Full Control",": Customize every layer of OS",[2353,5312],{},[93,5314,5315],{},"Powerful Graphics",": Hardware-accelerated UI with Qt Quick (QML)",[2353,5318],{},[93,5320,5321],{},"Networking",": Native TCP/IP, MQTT, Modbus support",[2353,5324],{},[93,5326,2852],{},": Secure software updates with A/B partition",[2353,5329],{},[93,5331,5332],{},"Long Lifespan",": Linux kernel and Qt, 10+ years support guarantee",[11,5335,5337],{"id":5336},"yocto-project-custom-linux-image","Yocto Project: Custom Linux Image",[24,5339,5341],{"id":5340},"what-is-yocto","What is Yocto?",[16,5343,5344,5345,5348],{},"Yocto Project is a build system for creating ",[93,5346,5347],{},"customized Linux distributions"," for embedded devices. Difference from standard Ubuntu/Debian:",[40,5350,5351,5357,5363],{},[43,5352,5353,5356],{},[93,5354,5355],{},"Minimal footprint",": Only needed packages included (~50MB rootfs)",[43,5358,5359,5362],{},[93,5360,5361],{},"Cross-compilation",": Compile for ARM processors on development PC (x86)",[43,5364,5365,5368],{},[93,5366,5367],{},"Reproducible builds",": Every build produces same result",[24,5370,5372],{"id":5371},"yocto-layer-structure-for-hmi","Yocto Layer Structure for HMI",[29,5374,5377],{"className":5375,"code":5376,"language":34},[32],"meta-hmi-amazeng/\n├── recipes-core/\n│   └── images/\n│       └── hmi-image.bb          # Main image recipe\n├── recipes-graphics/\n│   └── qt5/\n│       └── qtbase_%.bbappend     # Qt customizations\n├── recipes-connectivity/\n│   └── modbus/\n│       └── libmodbus_git.bb      # Modbus library\n├── recipes-kernel/\n│   └── linux/\n│       └── linux-%.bbappend      # Touchscreen drivers\n└── recipes-app/\n    └── hmi-app/\n        └── hmi-app_git.bb        # HMI application\n",[36,5378,5376],{"__ignoreMap":38},[24,5380,5382],{"id":5381},"example-hmi-image-recipe","Example HMI Image Recipe",[29,5384,5388],{"className":5385,"code":5386,"language":5387,"meta":38,"style":38},"language-bitbake shiki shiki-themes github-light github-dark","# hmi-image.bb\nDESCRIPTION = \"Amazeng HMI Linux Image\"\nLICENSE = \"MIT\"\n\nIMAGE_FEATURES += \" \\\n    splash \\\n    ssh-server-dropbear \\\n    hwcodecs \\\n\"\n\nIMAGE_INSTALL = \" \\\n    packagegroup-core-boot \\\n    qtbase \\\n    qtdeclarative \\\n    qtquickcontrols2 \\\n    qtgraphicaleffects \\\n    qtsvg \\\n    qtwebsockets \\\n    libmodbus \\\n    hmi-app \\\n    ca-certificates \\\n    tzdata \\\n\"\n\ninherit core-image\n","bitbake",[36,5389,5390,5395,5400,5405,5409,5414,5419,5424,5429,5434,5438,5443,5448,5453,5458,5463,5468,5473,5478,5483,5488,5493,5498,5502,5506],{"__ignoreMap":38},[270,5391,5392],{"class":272,"line":273},[270,5393,5394],{},"# hmi-image.bb\n",[270,5396,5397],{"class":272,"line":279},[270,5398,5399],{},"DESCRIPTION = \"Amazeng HMI Linux Image\"\n",[270,5401,5402],{"class":272,"line":285},[270,5403,5404],{},"LICENSE = \"MIT\"\n",[270,5406,5407],{"class":272,"line":291},[270,5408,775],{"emptyLinePlaceholder":524},[270,5410,5411],{"class":272,"line":297},[270,5412,5413],{},"IMAGE_FEATURES += \" \\\n",[270,5415,5416],{"class":272,"line":303},[270,5417,5418],{},"    splash \\\n",[270,5420,5421],{"class":272,"line":515},[270,5422,5423],{},"    ssh-server-dropbear \\\n",[270,5425,5426],{"class":272,"line":793},[270,5427,5428],{},"    hwcodecs \\\n",[270,5430,5431],{"class":272,"line":799},[270,5432,5433],{},"\"\n",[270,5435,5436],{"class":272,"line":805},[270,5437,775],{"emptyLinePlaceholder":524},[270,5439,5440],{"class":272,"line":2120},[270,5441,5442],{},"IMAGE_INSTALL = \" \\\n",[270,5444,5445],{"class":272,"line":2126},[270,5446,5447],{},"    packagegroup-core-boot \\\n",[270,5449,5450],{"class":272,"line":2132},[270,5451,5452],{},"    qtbase \\\n",[270,5454,5455],{"class":272,"line":3375},[270,5456,5457],{},"    qtdeclarative \\\n",[270,5459,5460],{"class":272,"line":3381},[270,5461,5462],{},"    qtquickcontrols2 \\\n",[270,5464,5465],{"class":272,"line":3387},[270,5466,5467],{},"    qtgraphicaleffects \\\n",[270,5469,5470],{"class":272,"line":3393},[270,5471,5472],{},"    qtsvg \\\n",[270,5474,5475],{"class":272,"line":3399},[270,5476,5477],{},"    qtwebsockets \\\n",[270,5479,5480],{"class":272,"line":3405},[270,5481,5482],{},"    libmodbus \\\n",[270,5484,5485],{"class":272,"line":3411},[270,5486,5487],{},"    hmi-app \\\n",[270,5489,5490],{"class":272,"line":3417},[270,5491,5492],{},"    ca-certificates \\\n",[270,5494,5495],{"class":272,"line":3423},[270,5496,5497],{},"    tzdata \\\n",[270,5499,5500],{"class":272,"line":3429},[270,5501,5433],{},[270,5503,5504],{"class":272,"line":3434},[270,5505,775],{"emptyLinePlaceholder":524},[270,5507,5508],{"class":272,"line":3440},[270,5509,5510],{},"inherit core-image\n",[11,5512,5514],{"id":5513},"modern-hmi-interface-with-qtqml","Modern HMI Interface with Qt/QML",[24,5516,5518],{"id":5517},"qt-quick-qml-vs-qt-widgets","Qt Quick (QML) vs Qt Widgets",[636,5520,5521,5533],{},[639,5522,5523],{},[642,5524,5525,5527,5530],{},[645,5526,647],{},[645,5528,5529],{},"Qt Widgets (C++)",[645,5531,5532],{},"Qt Quick (QML)",[655,5534,5535,5547,5560,5573,5585],{},[642,5536,5537,5541,5544],{},[660,5538,5539],{},[93,5540,2239],{},[660,5542,5543],{},"CPU-based",[660,5545,5546],{},"GPU-accelerated",[642,5548,5549,5554,5557],{},[660,5550,5551],{},[93,5552,5553],{},"Development Speed",[660,5555,5556],{},"Slow (compile)",[660,5558,5559],{},"Fast (interpreted)",[642,5561,5562,5567,5570],{},[660,5563,5564],{},[93,5565,5566],{},"Animation",[660,5568,5569],{},"Complex",[660,5571,5572],{},"Very easy",[642,5574,5575,5579,5582],{},[660,5576,5577],{},[93,5578,3016],{},[660,5580,5581],{},"Mouse events",[660,5583,5584],{},"Native touch",[642,5586,5587,5592,5594],{},[660,5588,5589],{},[93,5590,5591],{},"Designer Support",[660,5593,249],{},[660,5595,5596],{},"Qt Design Studio",[16,5598,5599,5602],{},[93,5600,5601],{},"Qt Quick (QML) should definitely be preferred"," for HMI applications.",[24,5604,5606],{"id":5605},"simple-hmi-application-loadcell-reader","Simple HMI Application: Loadcell Reader",[16,5608,5609,5610,5612],{},"HMI reading weight from ",[463,5611,471],{"href":1723}," via Modbus TCP:",[16,5614,5615],{},[93,5616,5617],{},"main.qml",[29,5619,5623],{"className":5620,"code":5621,"language":5622,"meta":38,"style":38},"language-qml shiki shiki-themes github-light github-dark","import QtQuick 2.15\nimport QtQuick.Controls 2.15\nimport QtQuick.Layouts 1.15\n\nApplicationWindow {\n    visible: true\n    width: 1024\n    height: 600\n    title: \"GDT Loadcell Monitor\"\n\n    // Background gradient\n    Rectangle {\n        anchors.fill: parent\n        gradient: Gradient {\n            GradientStop { position: 0.0; color: \"#2C3E50\" }\n            GradientStop { position: 1.0; color: \"#34495E\" }\n        }\n    }\n\n    ColumnLayout {\n        anchors.centerIn: parent\n        spacing: 30\n\n        // Title\n        Text {\n            text: \"Tank 1 - Net Weight\"\n            font.pixelSize: 36\n            font.bold: true\n            color: \"#ECF0F1\"\n            Layout.alignment: Qt.AlignHCenter\n        }\n\n        // Weight display\n        Rectangle {\n            width: 600\n            height: 200\n            color: \"#1ABC9C\"\n            radius: 20\n\n            Text {\n                anchors.centerIn: parent\n                text: modbusBackend.weight.toFixed(2) + \" kg\"\n                font.pixelSize: 72\n                font.bold: true\n                color: \"white\"\n            }\n        }\n\n        // Control buttons\n        RowLayout {\n            Layout.alignment: Qt.AlignHCenter\n            spacing: 20\n\n            Button {\n                text: \"TARE\"\n                font.pixelSize: 24\n                implicitWidth: 150\n                implicitHeight: 80\n                onClicked: modbusBackend.tare()\n            }\n\n            Button {\n                text: \"ZERO\"\n                font.pixelSize: 24\n                implicitWidth: 150\n                implicitHeight: 80\n                onClicked: modbusBackend.zero()\n            }\n        }\n    }\n}\n","qml",[36,5624,5625,5630,5635,5640,5644,5649,5654,5659,5664,5669,5673,5678,5683,5688,5693,5698,5703,5707,5711,5715,5720,5725,5730,5734,5739,5744,5749,5754,5759,5764,5769,5773,5777,5782,5787,5792,5797,5802,5807,5811,5816,5821,5826,5831,5836,5841,5845,5849,5853,5858,5863,5867,5872,5876,5881,5886,5891,5896,5901,5906,5910,5914,5918,5923,5927,5931,5935,5940,5944,5948,5952],{"__ignoreMap":38},[270,5626,5627],{"class":272,"line":273},[270,5628,5629],{},"import QtQuick 2.15\n",[270,5631,5632],{"class":272,"line":279},[270,5633,5634],{},"import QtQuick.Controls 2.15\n",[270,5636,5637],{"class":272,"line":285},[270,5638,5639],{},"import QtQuick.Layouts 1.15\n",[270,5641,5642],{"class":272,"line":291},[270,5643,775],{"emptyLinePlaceholder":524},[270,5645,5646],{"class":272,"line":297},[270,5647,5648],{},"ApplicationWindow {\n",[270,5650,5651],{"class":272,"line":303},[270,5652,5653],{},"    visible: true\n",[270,5655,5656],{"class":272,"line":515},[270,5657,5658],{},"    width: 1024\n",[270,5660,5661],{"class":272,"line":793},[270,5662,5663],{},"    height: 600\n",[270,5665,5666],{"class":272,"line":799},[270,5667,5668],{},"    title: \"GDT Loadcell Monitor\"\n",[270,5670,5671],{"class":272,"line":805},[270,5672,775],{"emptyLinePlaceholder":524},[270,5674,5675],{"class":272,"line":2120},[270,5676,5677],{},"    // Background gradient\n",[270,5679,5680],{"class":272,"line":2126},[270,5681,5682],{},"    Rectangle {\n",[270,5684,5685],{"class":272,"line":2132},[270,5686,5687],{},"        anchors.fill: parent\n",[270,5689,5690],{"class":272,"line":3375},[270,5691,5692],{},"        gradient: Gradient {\n",[270,5694,5695],{"class":272,"line":3381},[270,5696,5697],{},"            GradientStop { position: 0.0; color: \"#2C3E50\" }\n",[270,5699,5700],{"class":272,"line":3387},[270,5701,5702],{},"            GradientStop { position: 1.0; color: \"#34495E\" }\n",[270,5704,5705],{"class":272,"line":3393},[270,5706,4491],{},[270,5708,5709],{"class":272,"line":3399},[270,5710,3795],{},[270,5712,5713],{"class":272,"line":3405},[270,5714,775],{"emptyLinePlaceholder":524},[270,5716,5717],{"class":272,"line":3411},[270,5718,5719],{},"    ColumnLayout {\n",[270,5721,5722],{"class":272,"line":3417},[270,5723,5724],{},"        anchors.centerIn: parent\n",[270,5726,5727],{"class":272,"line":3423},[270,5728,5729],{},"        spacing: 30\n",[270,5731,5732],{"class":272,"line":3429},[270,5733,775],{"emptyLinePlaceholder":524},[270,5735,5736],{"class":272,"line":3434},[270,5737,5738],{},"        // Title\n",[270,5740,5741],{"class":272,"line":3440},[270,5742,5743],{},"        Text {\n",[270,5745,5746],{"class":272,"line":3446},[270,5747,5748],{},"            text: \"Tank 1 - Net Weight\"\n",[270,5750,5751],{"class":272,"line":3452},[270,5752,5753],{},"            font.pixelSize: 36\n",[270,5755,5756],{"class":272,"line":3457},[270,5757,5758],{},"            font.bold: true\n",[270,5760,5761],{"class":272,"line":3463},[270,5762,5763],{},"            color: \"#ECF0F1\"\n",[270,5765,5766],{"class":272,"line":3469},[270,5767,5768],{},"            Layout.alignment: Qt.AlignHCenter\n",[270,5770,5771],{"class":272,"line":3475},[270,5772,4491],{},[270,5774,5775],{"class":272,"line":3480},[270,5776,775],{"emptyLinePlaceholder":524},[270,5778,5779],{"class":272,"line":3486},[270,5780,5781],{},"        // Weight display\n",[270,5783,5784],{"class":272,"line":3492},[270,5785,5786],{},"        Rectangle {\n",[270,5788,5789],{"class":272,"line":3497},[270,5790,5791],{},"            width: 600\n",[270,5793,5794],{"class":272,"line":3503},[270,5795,5796],{},"            height: 200\n",[270,5798,5799],{"class":272,"line":3509},[270,5800,5801],{},"            color: \"#1ABC9C\"\n",[270,5803,5804],{"class":272,"line":3515},[270,5805,5806],{},"            radius: 20\n",[270,5808,5809],{"class":272,"line":3521},[270,5810,775],{"emptyLinePlaceholder":524},[270,5812,5813],{"class":272,"line":3527},[270,5814,5815],{},"            Text {\n",[270,5817,5818],{"class":272,"line":3532},[270,5819,5820],{},"                anchors.centerIn: parent\n",[270,5822,5823],{"class":272,"line":3538},[270,5824,5825],{},"                text: modbusBackend.weight.toFixed(2) + \" kg\"\n",[270,5827,5828],{"class":272,"line":3544},[270,5829,5830],{},"                font.pixelSize: 72\n",[270,5832,5833],{"class":272,"line":3550},[270,5834,5835],{},"                font.bold: true\n",[270,5837,5838],{"class":272,"line":3556},[270,5839,5840],{},"                color: \"white\"\n",[270,5842,5843],{"class":272,"line":3562},[270,5844,4592],{},[270,5846,5847],{"class":272,"line":3568},[270,5848,4491],{},[270,5850,5851],{"class":272,"line":3574},[270,5852,775],{"emptyLinePlaceholder":524},[270,5854,5855],{"class":272,"line":3580},[270,5856,5857],{},"        // Control buttons\n",[270,5859,5860],{"class":272,"line":3586},[270,5861,5862],{},"        RowLayout {\n",[270,5864,5865],{"class":272,"line":3592},[270,5866,5768],{},[270,5868,5869],{"class":272,"line":3597},[270,5870,5871],{},"            spacing: 20\n",[270,5873,5874],{"class":272,"line":3603},[270,5875,775],{"emptyLinePlaceholder":524},[270,5877,5878],{"class":272,"line":3609},[270,5879,5880],{},"            Button {\n",[270,5882,5883],{"class":272,"line":3615},[270,5884,5885],{},"                text: \"TARE\"\n",[270,5887,5888],{"class":272,"line":3621},[270,5889,5890],{},"                font.pixelSize: 24\n",[270,5892,5893],{"class":272,"line":3627},[270,5894,5895],{},"                implicitWidth: 150\n",[270,5897,5898],{"class":272,"line":3633},[270,5899,5900],{},"                implicitHeight: 80\n",[270,5902,5903],{"class":272,"line":3639},[270,5904,5905],{},"                onClicked: modbusBackend.tare()\n",[270,5907,5908],{"class":272,"line":3645},[270,5909,4592],{},[270,5911,5912],{"class":272,"line":3651},[270,5913,775],{"emptyLinePlaceholder":524},[270,5915,5916],{"class":272,"line":3657},[270,5917,5880],{},[270,5919,5920],{"class":272,"line":3663},[270,5921,5922],{},"                text: \"ZERO\"\n",[270,5924,5925],{"class":272,"line":3669},[270,5926,5890],{},[270,5928,5929],{"class":272,"line":3675},[270,5930,5895],{},[270,5932,5933],{"class":272,"line":3681},[270,5934,5900],{},[270,5936,5937],{"class":272,"line":3687},[270,5938,5939],{},"                onClicked: modbusBackend.zero()\n",[270,5941,5942],{"class":272,"line":3693},[270,5943,4592],{},[270,5945,5946],{"class":272,"line":3698},[270,5947,4491],{},[270,5949,5950],{"class":272,"line":3704},[270,5951,3795],{},[270,5953,5954],{"class":272,"line":3710},[270,5955,2129],{},[11,5957,5959],{"id":5958},"real-world-application-multi-tank-monitoring","Real World Application: Multi-Tank Monitoring",[24,5961,3294],{"id":3293},[16,5963,5964,5965,5967],{},"3 milk tanks, each with ",[463,5966,471],{"href":1723}," + 4 loadcells. Monitoring all tanks with a central 10.1\" HMI.",[24,5969,5971],{"id":5970},"architecture","Architecture",[29,5973,5976],{"className":5974,"code":5975,"language":34},[32],"┌──────────────┐    Modbus TCP     ┌──────────────┐\n│  Tank 1 GDT  │◄─────────────────►│              │\n│ 192.168.1.101│                   │              │\n└──────────────┘                   │   HMI Panel  │\n                                   │  (10.1 inch) │\n┌──────────────┐    Modbus TCP     │   Qt/QML     │\n│  Tank 2 GDT  │◄─────────────────►│              │\n│ 192.168.1.102│                   │              │\n└──────────────┘                   └──────────────┘\n",[36,5977,5975],{"__ignoreMap":38},[11,5979,5981],{"id":5980},"cloud-integration-hmi-aws-iot","Cloud Integration: HMI + AWS IoT",[16,5983,5984,5985,5988,5989,5991],{},"HMI panel can also work as an ",[93,5986,5987],{},"IoT gateway",". In our ",[463,5990,2983],{"href":2634}," solution, HMI:",[176,5993,5994,6005,6011],{},[43,5995,5996,5997,467,5999,6001,6002],{},"Collects data from ",[463,5998,1360],{"href":1613},[463,6000,2840],{"href":1723}," devices via ",[93,6003,6004],{},"Modbus RTU/TCP",[43,6006,6007,6008],{},"Sends to AWS IoT Core via ",[93,6009,6010],{},"MQTT",[43,6012,6013,6014,467,6017],{},"Displays both on ",[93,6015,6016],{},"local interface",[93,6018,6019],{},"Grafana dashboard",[16,6021,6022],{},[93,6023,6024],{},"Qt MQTT Client Example:",[29,6026,6028],{"className":264,"code":6027,"language":266,"meta":38,"style":38},"#include \u003CQtMqtt/QMqttClient>\n\nQMqttClient *mqttClient = new QMqttClient(this);\nmqttClient->setHostname(\"xxxxx.iot.eu-west-1.amazonaws.com\");\nmqttClient->setPort(8883);\nmqttClient->connectToHost();\n\n// Publish data read from GDT\nQByteArray payload = QString(\"{\\\"tank_id\\\":1,\\\"weight\\\":%1}\").arg(weight).toUtf8();\nmqttClient->publish(\"amazeng/tank/data\", payload);\n",[36,6029,6030,6035,6039,6044,6049,6054,6059,6063,6068,6073],{"__ignoreMap":38},[270,6031,6032],{"class":272,"line":273},[270,6033,6034],{},"#include \u003CQtMqtt/QMqttClient>\n",[270,6036,6037],{"class":272,"line":279},[270,6038,775],{"emptyLinePlaceholder":524},[270,6040,6041],{"class":272,"line":285},[270,6042,6043],{},"QMqttClient *mqttClient = new QMqttClient(this);\n",[270,6045,6046],{"class":272,"line":291},[270,6047,6048],{},"mqttClient->setHostname(\"xxxxx.iot.eu-west-1.amazonaws.com\");\n",[270,6050,6051],{"class":272,"line":297},[270,6052,6053],{},"mqttClient->setPort(8883);\n",[270,6055,6056],{"class":272,"line":303},[270,6057,6058],{},"mqttClient->connectToHost();\n",[270,6060,6061],{"class":272,"line":515},[270,6062,775],{"emptyLinePlaceholder":524},[270,6064,6065],{"class":272,"line":793},[270,6066,6067],{},"// Publish data read from GDT\n",[270,6069,6070],{"class":272,"line":799},[270,6071,6072],{},"QByteArray payload = QString(\"{\\\"tank_id\\\":1,\\\"weight\\\":%1}\").arg(weight).toUtf8();\n",[270,6074,6075],{"class":272,"line":805},[270,6076,6077],{},"mqttClient->publish(\"amazeng/tank/data\", payload);\n",[11,6079,444],{"id":443},[16,6081,6082,6083,6086,6087,6089],{},"The Embedded Linux + Qt combination is the ",[93,6084,6085],{},"most flexible and powerful solution"," for modern industrial HMIs. Our ",[463,6088,2465],{"href":2464}," are built on this technology stack and:",[16,6091,6092,6093,6095,6096,6098,6099,6101],{},"✅ 70% more economical than proprietary solutions",[2353,6094],{},"\n✅ Full customization freedom",[2353,6097],{},"\n✅ 10+ years long-term support guarantee",[2353,6100],{},"\n✅ Ready for Cloud and IoT integration",[24,6103,5132],{"id":5131},[40,6105,6106,6111,6118,6122],{},[43,6107,6108],{},[463,6109,6110],{"href":5236},"Embedded Linux with Yocto",[43,6112,6113,6117],{},[463,6114,6116],{"href":6115},"/en/blog/why-we-use-zephyr-rtos","Why We Use Zephyr RTOS"," (alternative RTOS approach)",[43,6119,6120],{},[463,6121,2465],{"href":2464},[43,6123,6124],{},[463,6125,2983],{"href":2634},[477,6127,479],{},{"title":38,"searchDepth":279,"depth":279,"links":6129},[6130,6131,6135,6140,6144,6148,6149],{"id":13,"depth":279,"text":14},{"id":5241,"depth":279,"text":5242,"children":6132},[6133,6134],{"id":5245,"depth":285,"text":5246},{"id":5297,"depth":285,"text":5298},{"id":5336,"depth":279,"text":5337,"children":6136},[6137,6138,6139],{"id":5340,"depth":285,"text":5341},{"id":5371,"depth":285,"text":5372},{"id":5381,"depth":285,"text":5382},{"id":5513,"depth":279,"text":5514,"children":6141},[6142,6143],{"id":5517,"depth":285,"text":5518},{"id":5605,"depth":285,"text":5606},{"id":5958,"depth":279,"text":5959,"children":6145},[6146,6147],{"id":3293,"depth":285,"text":3294},{"id":5970,"depth":285,"text":5971},{"id":5980,"depth":279,"text":5981},{"id":443,"depth":279,"text":444,"children":6150},[6151],{"id":5131,"depth":285,"text":5132},"Complete guide for developing customized industrial interfaces using Yocto Project and Qt/QML in Linux-based HMI systems.",{"date":3011,"author":514,"readTime":805,"featured":524,"tags":6154},[2820,518,5226,521,255,6155,3016],"Industrial UI","/en/blog/embedded-linux-hmi-development-yocto-qt",{"title":5203,"description":6152},"en/blog/embedded-linux-hmi-development-yocto-qt","7macDMOyCxSm_uvH78y_GFJh8oXP_IS5k1_2sx_ttM8",{"id":6161,"title":6162,"body":6163,"description":7981,"extension":511,"meta":7982,"navigation":524,"path":2324,"seo":7989,"stem":7990,"__hash__":7991},"en_blog/en/blog/fully-integrated-solution-zma-gdt-hmi-aws.md","Fully Integrated Solution: ZMA + HMI + AWS for Weighing Systems",{"type":8,"value":6164,"toc":7958},[6165,6167,6185,6194,6198,6202,6228,6232,6270,6272,6278,6282,6286,6291,6569,6574,6588,6593,6597,6602,6622,6627,6650,6654,6659,6673,6678,6692,6696,6700,6705,7048,7052,7057,7677,7681,7685,7690,7735,7741,7746,7864,7866,7869,7905,7910,7927,7931,7955],[11,6166,14],{"id":13},[16,6168,6169,6170,6173,6174,6177,6178,6180,6181,467,6183,472],{},"In modern industrial facilities, obtaining ",[93,6171,6172],{},"full control"," requires the integration of multiple hardware and software components. In this article, we examine in detail a ",[93,6175,6176],{},"fully integrated solution"," using our ",[463,6179,466],{"href":1613},", ",[463,6182,2465],{"href":2464},[463,6184,2983],{"href":2634},[16,6186,6187,6190,6191,6193],{},[93,6188,6189],{},"Note:"," Our ",[463,6192,471],{"href":1723}," supports maximum 2 channels + 3 DIO. For 4-loadcell applications, ZMA-4 is the preferred choice.",[11,6195,6197],{"id":6196},"real-world-scenario-milk-processing-facility","Real-World Scenario: Milk Processing Facility",[24,6199,6201],{"id":6200},"facility-profile","Facility Profile",[40,6203,6204,6210,6216,6222],{},[43,6205,6206,6209],{},[93,6207,6208],{},"Location:"," Istanbul, Turkey",[43,6211,6212,6215],{},[93,6213,6214],{},"Capacity:"," 5 milk collection tanks (5,000 kg each)",[43,6217,6218,6221],{},[93,6219,6220],{},"Operation:"," 24/7 continuous operation",[43,6223,6224,6227],{},[93,6225,6226],{},"Compliance:"," ISO 22000, HACCP requirements",[24,6229,6231],{"id":6230},"requirements","Requirements",[176,6233,6234,6240,6246,6252,6258,6264],{},[43,6235,6236,6239],{},[93,6237,6238],{},"Real-time Weight Monitoring:"," Weight of each tank updated every second",[43,6241,6242,6245],{},[93,6243,6244],{},"Local Display:"," Touchscreen HMI panel per tank",[43,6247,6248,6251],{},[93,6249,6250],{},"Central Control:"," Large central HMI screen (10.1\")",[43,6253,6254,6257],{},[93,6255,6256],{},"Cloud Data:"," Historical data on AWS for quality reports",[43,6259,6260,6263],{},[93,6261,6262],{},"Alarms:"," SMS and email alerts when tank capacity exceeds 90%",[43,6265,6266,6269],{},[93,6267,6268],{},"Traceability:"," Weight history per batch (which milk came in when, how long did it stay)",[11,6271,3280],{"id":3279},[29,6273,6276],{"className":6274,"code":6275,"language":34},[32],"┌─────────────────────────────────────────────────────────────┐\n│                   Milk Processing Facility                  │\n│                                                             │\n│  ┌────────────┐  ┌────────────┐  ┌────────────┐           │\n│  │  Tank 1    │  │  Tank 2    │  │  Tank 3    │           │\n│  │  5000 kg   │  │  5000 kg   │  │  5000 kg   │           │\n│  │            │  │            │  │            │           │\n│  │ 4x Loadcell│  │ 4x Loadcell│  │ 4x Loadcell│           │\n│  └──────┬─────┘  └──────┬─────┘  └──────┬─────┘           │\n│         │                │                │                │\n│    ┌────▼────┐      ┌────▼────┐      ┌────▼────┐          │\n│    │ ZMA-4-01 │      │ ZMA-4-02 │      │ ZMA-4-03 │          │\n│    │  .101    │      │  .102    │      │  .103    │          │\n│    └────┬────┘      └────┬────┘      └────┬────┘          │\n│         │                │                │                │\n│    ┌────▼────┐      ┌────▼────┐      ┌────▼────┐          │\n│    │7\" HMI   │      │7\" HMI   │      │7\" HMI   │          │\n│    │Touch    │      │Touch    │      │Touch    │          │\n│    └────┬────┘      └────┬────┘      └────┬────┘          │\n│         │                │                │                │\n│         └────────────────┼────────────────┘                │\n│                          │                                 │\n│                    ┌─────▼──────┐                          │\n│                    │  Ethernet  │                          │\n│                    │  Switch    │                          │\n│                    └─────┬──────┘                          │\n│                          │                                 │\n│          ┌───────────────┼───────────────┐                │\n│          │               │               │                │\n│     ┌────▼────┐    ┌─────▼─────┐   ┌────▼────┐           │\n│     │10.1\" HMI│    │  Gateway  │   │  ZMA-4  │           │\n│     │Central  │    │Raspberry  │   │(Analog) │           │\n│     │Monitor  │    │   Pi 4    │   └─────────┘           │\n│     └─────────┘    └─────┬─────┘                          │\n│                          │                                 │\n└──────────────────────────┼─────────────────────────────────┘\n                           │ MQTT over TLS\n                           │ Port 8883\n                           ▼\n                  ┌────────────────────┐\n                  │    AWS Cloud       │\n                  │                    │\n                  │  ┌──────────────┐  │\n                  │  │  IoT Core    │  │\n                  │  └──────┬───────┘  │\n                  │         │          │\n                  │  ┌──────▼───────┐  │\n                  │  │ Timestream   │  │\n                  │  │ (Database)   │  │\n                  │  └──────┬───────┘  │\n                  │         │          │\n                  │  ┌──────▼───────┐  │\n                  │  │  Grafana     │  │\n                  │  │  Dashboard   │  │\n                  │  └──────────────┘  │\n                  └────────────────────┘\n",[36,6277,6275],{"__ignoreMap":38},[11,6279,6281],{"id":6280},"hardware-configuration","Hardware Configuration",[24,6283,6285],{"id":6284},"_1-zma-4-data-acquisition-modules-3-units","1. ZMA-4 Data Acquisition Modules (3 units)",[16,6287,6288],{},[93,6289,6290],{},"Configuration per Tank:",[29,6292,6294],{"className":3803,"code":6293,"language":3805,"meta":38,"style":38},"{\n  \"device\": \"ZMA-4\",\n  \"channels\": 4,\n  \"loadcells\": [\n    { \"position\": \"Front-Left\", \"capacity\": \"2000kg\", \"sensitivity\": \"2mV/V\" },\n    { \"position\": \"Front-Right\", \"capacity\": \"2000kg\", \"sensitivity\": \"2mV/V\" },\n    { \"position\": \"Rear-Left\", \"capacity\": \"2000kg\", \"sensitivity\": \"2mV/V\" },\n    { \"position\": \"Rear-Right\", \"capacity\": \"2000kg\", \"sensitivity\": \"2mV/V\" }\n  ],\n  \"modbus\": {\n    \"type\": \"TCP\",\n    \"ip\": \"192.168.1.101\",\n    \"port\": 502,\n    \"unit_id\": 1\n  },\n  \"specs\": {\n    \"adc_resolution\": \"24-bit\",\n    \"sampling_rate\": \"1000 SPS\",\n    \"accuracy\": \"±0.02%\"\n  }\n}\n",[36,6295,6296,6300,6312,6324,6332,6368,6397,6426,6456,6461,6469,6481,6493,6505,6515,6519,6526,6538,6550,6560,6565],{"__ignoreMap":38},[270,6297,6298],{"class":272,"line":273},[270,6299,3812],{"class":1918},[270,6301,6302,6305,6307,6310],{"class":272,"line":279},[270,6303,6304],{"class":2053},"  \"device\"",[270,6306,1927],{"class":1918},[270,6308,6309],{"class":1930},"\"ZMA-4\"",[270,6311,3825],{"class":1918},[270,6313,6314,6317,6319,6322],{"class":272,"line":285},[270,6315,6316],{"class":2053},"  \"channels\"",[270,6318,1927],{"class":1918},[270,6320,6321],{"class":2053},"4",[270,6323,3825],{"class":1918},[270,6325,6326,6329],{"class":272,"line":291},[270,6327,6328],{"class":2053},"  \"loadcells\"",[270,6330,6331],{"class":1918},": [\n",[270,6333,6334,6337,6340,6342,6345,6347,6350,6352,6355,6357,6360,6362,6365],{"class":272,"line":297},[270,6335,6336],{"class":1918},"    { ",[270,6338,6339],{"class":2053},"\"position\"",[270,6341,1927],{"class":1918},[270,6343,6344],{"class":1930},"\"Front-Left\"",[270,6346,6180],{"class":1918},[270,6348,6349],{"class":2053},"\"capacity\"",[270,6351,1927],{"class":1918},[270,6353,6354],{"class":1930},"\"2000kg\"",[270,6356,6180],{"class":1918},[270,6358,6359],{"class":2053},"\"sensitivity\"",[270,6361,1927],{"class":1918},[270,6363,6364],{"class":1930},"\"2mV/V\"",[270,6366,6367],{"class":1918}," },\n",[270,6369,6370,6372,6374,6376,6379,6381,6383,6385,6387,6389,6391,6393,6395],{"class":272,"line":303},[270,6371,6336],{"class":1918},[270,6373,6339],{"class":2053},[270,6375,1927],{"class":1918},[270,6377,6378],{"class":1930},"\"Front-Right\"",[270,6380,6180],{"class":1918},[270,6382,6349],{"class":2053},[270,6384,1927],{"class":1918},[270,6386,6354],{"class":1930},[270,6388,6180],{"class":1918},[270,6390,6359],{"class":2053},[270,6392,1927],{"class":1918},[270,6394,6364],{"class":1930},[270,6396,6367],{"class":1918},[270,6398,6399,6401,6403,6405,6408,6410,6412,6414,6416,6418,6420,6422,6424],{"class":272,"line":515},[270,6400,6336],{"class":1918},[270,6402,6339],{"class":2053},[270,6404,1927],{"class":1918},[270,6406,6407],{"class":1930},"\"Rear-Left\"",[270,6409,6180],{"class":1918},[270,6411,6349],{"class":2053},[270,6413,1927],{"class":1918},[270,6415,6354],{"class":1930},[270,6417,6180],{"class":1918},[270,6419,6359],{"class":2053},[270,6421,1927],{"class":1918},[270,6423,6364],{"class":1930},[270,6425,6367],{"class":1918},[270,6427,6428,6430,6432,6434,6437,6439,6441,6443,6445,6447,6449,6451,6453],{"class":272,"line":793},[270,6429,6336],{"class":1918},[270,6431,6339],{"class":2053},[270,6433,1927],{"class":1918},[270,6435,6436],{"class":1930},"\"Rear-Right\"",[270,6438,6180],{"class":1918},[270,6440,6349],{"class":2053},[270,6442,1927],{"class":1918},[270,6444,6354],{"class":1930},[270,6446,6180],{"class":1918},[270,6448,6359],{"class":2053},[270,6450,1927],{"class":1918},[270,6452,6364],{"class":1930},[270,6454,6455],{"class":1918}," }\n",[270,6457,6458],{"class":272,"line":799},[270,6459,6460],{"class":1918},"  ],\n",[270,6462,6463,6466],{"class":272,"line":805},[270,6464,6465],{"class":2053},"  \"modbus\"",[270,6467,6468],{"class":1918},": {\n",[270,6470,6471,6474,6476,6479],{"class":272,"line":2120},[270,6472,6473],{"class":2053},"    \"type\"",[270,6475,1927],{"class":1918},[270,6477,6478],{"class":1930},"\"TCP\"",[270,6480,3825],{"class":1918},[270,6482,6483,6486,6488,6491],{"class":272,"line":2126},[270,6484,6485],{"class":2053},"    \"ip\"",[270,6487,1927],{"class":1918},[270,6489,6490],{"class":1930},"\"192.168.1.101\"",[270,6492,3825],{"class":1918},[270,6494,6495,6498,6500,6503],{"class":272,"line":2132},[270,6496,6497],{"class":2053},"    \"port\"",[270,6499,1927],{"class":1918},[270,6501,6502],{"class":2053},"502",[270,6504,3825],{"class":1918},[270,6506,6507,6510,6512],{"class":272,"line":3375},[270,6508,6509],{"class":2053},"    \"unit_id\"",[270,6511,1927],{"class":1918},[270,6513,6514],{"class":2053},"1\n",[270,6516,6517],{"class":272,"line":3381},[270,6518,2098],{"class":1918},[270,6520,6521,6524],{"class":272,"line":3387},[270,6522,6523],{"class":2053},"  \"specs\"",[270,6525,6468],{"class":1918},[270,6527,6528,6531,6533,6536],{"class":272,"line":3393},[270,6529,6530],{"class":2053},"    \"adc_resolution\"",[270,6532,1927],{"class":1918},[270,6534,6535],{"class":1930},"\"24-bit\"",[270,6537,3825],{"class":1918},[270,6539,6540,6543,6545,6548],{"class":272,"line":3399},[270,6541,6542],{"class":2053},"    \"sampling_rate\"",[270,6544,1927],{"class":1918},[270,6546,6547],{"class":1930},"\"1000 SPS\"",[270,6549,3825],{"class":1918},[270,6551,6552,6555,6557],{"class":272,"line":3405},[270,6553,6554],{"class":2053},"    \"accuracy\"",[270,6556,1927],{"class":1918},[270,6558,6559],{"class":1930},"\"±0.02%\"\n",[270,6561,6562],{"class":272,"line":3411},[270,6563,6564],{"class":1918},"  }\n",[270,6566,6567],{"class":272,"line":3417},[270,6568,2129],{"class":1918},[16,6570,6571],{},[93,6572,6573],{},"Why ZMA-4 for this application:",[40,6575,6576,6579,6582,6585],{},[43,6577,6578],{},"✅ 4 independent channels (perfect for 4-loadcell tanks)",[43,6580,6581],{},"✅ 24-bit ADC per channel (high precision)",[43,6583,6584],{},"✅ Modbus TCP/RTU support (easy gateway integration)",[43,6586,6587],{},"✅ High sampling rate (up to 1000 SPS)",[16,6589,6590,6592],{},[93,6591,6189],{}," GDT Digital Transmitter supports maximum 2 channels + 3 DIO, making it suitable for simpler applications with 1-2 loadcells.",[24,6594,6596],{"id":6595},"_2-hmi-panel","2. HMI Panel",[16,6598,6599],{},[93,6600,6601],{},"Central HMI (1x 10.1\" panel):",[40,6603,6604,6607,6610,6613,6616,6619],{},[43,6605,6606],{},"All tank weights overview",[43,6608,6609],{},"Real-time weight display for each tank",[43,6611,6612],{},"Historical trend charts (last 24 hours)",[43,6614,6615],{},"Alarm history",[43,6617,6618],{},"Tare/Zero controls",[43,6620,6621],{},"System diagnostics",[16,6623,6624],{},[93,6625,6626],{},"Technical Specs:",[40,6628,6629,6632,6635,6638,6641,6644,6647],{},[43,6630,6631],{},"Processor: ARM Cortex-A53 (4-core, 1.2 GHz)",[43,6633,6634],{},"RAM: 1 GB DDR3",[43,6636,6637],{},"Storage: 8 GB eMMC",[43,6639,6640],{},"Display: 10.1\" Capacitive touchscreen (1280x800)",[43,6642,6643],{},"OS: Embedded Linux (Yocto)",[43,6645,6646],{},"Software: Qt 5.15 + QML",[43,6648,6649],{},"Network: Ethernet (Modbus TCP client)",[24,6651,6653],{"id":6652},"_3-iot-gateway-raspberry-pi-4","3. IoT Gateway (Raspberry Pi 4)",[16,6655,6656],{},[93,6657,6658],{},"Role:",[40,6660,6661,6664,6667,6670],{},[43,6662,6663],{},"Collect data from 3 ZMA-4 devices (Modbus TCP)",[43,6665,6666],{},"Convert protocol (Modbus → MQTT)",[43,6668,6669],{},"Send to AWS IoT Core",[43,6671,6672],{},"Local data backup (SQLite)",[16,6674,6675],{},[93,6676,6677],{},"Specs:",[40,6679,6680,6683,6686,6689],{},[43,6681,6682],{},"Raspberry Pi 4 Model B (4GB RAM)",[43,6684,6685],{},"32GB SD card (Industrial grade)",[43,6687,6688],{},"Ethernet connection (no WiFi)",[43,6690,6691],{},"Custom Python gateway software",[11,6693,6695],{"id":6694},"software-architecture","Software Architecture",[24,6697,6699],{"id":6698},"local-hmi-application-qtqml","Local HMI Application (Qt/QML)",[16,6701,6702],{},[93,6703,6704],{},"Tank Monitor Screen:",[29,6706,6708],{"className":5620,"code":6707,"language":5622,"meta":38,"style":38},"// TankView.qml\nRectangle {\n    width: 800\n    height: 480\n    color: \"#2C3E50\"\n\n    property int tankId: 1\n    property real weight: 0.0\n    property real capacity: 5000.0\n    property real fillPercent: (weight / capacity) * 100\n\n    ColumnLayout {\n        anchors.fill: parent\n        anchors.margins: 20\n\n        // Tank visualization\n        Rectangle {\n            Layout.fillWidth: true\n            Layout.preferredHeight: 300\n            color: \"transparent\"\n            border.color: \"#ECF0F1\"\n            border.width: 3\n\n            // Fill level\n            Rectangle {\n                anchors.bottom: parent.bottom\n                anchors.left: parent.left\n                anchors.right: parent.right\n                height: parent.height * (fillPercent / 100)\n                color: fillPercent > 90 ? \"#E74C3C\" : \"#3498DB\"\n\n                Behavior on height {\n                    NumberAnimation { duration: 300 }\n                }\n            }\n\n            // Weight text\n            Text {\n                anchors.centerIn: parent\n                text: weight.toFixed(1) + \" kg\"\n                font.pixelSize: 64\n                font.bold: true\n                color: \"white\"\n            }\n        }\n\n        // Percentage bar\n        ProgressBar {\n            Layout.fillWidth: true\n            value: fillPercent / 100\n\n            background: Rectangle {\n                color: \"#34495E\"\n                radius: 5\n            }\n\n            contentItem: Item {\n                Rectangle {\n                    width: parent.width * parent.parent.value\n                    height: parent.height\n                    color: parent.parent.value > 0.9 ? \"#E74C3C\" : \"#2ECC71\"\n                    radius: 5\n                }\n            }\n        }\n\n        Text {\n            text: fillPercent.toFixed(1) + \"% Full\"\n            font.pixelSize: 24\n            color: \"#ECF0F1\"\n            Layout.alignment: Qt.AlignHCenter\n        }\n    }\n}\n",[36,6709,6710,6715,6720,6725,6730,6735,6739,6744,6749,6754,6759,6763,6767,6771,6776,6780,6785,6789,6794,6799,6804,6809,6814,6818,6823,6828,6833,6838,6843,6848,6853,6857,6862,6867,6871,6875,6879,6884,6888,6892,6897,6902,6906,6910,6914,6918,6922,6927,6932,6936,6941,6945,6950,6955,6960,6964,6968,6973,6978,6983,6988,6993,6998,7002,7006,7010,7014,7018,7023,7028,7032,7036,7040,7044],{"__ignoreMap":38},[270,6711,6712],{"class":272,"line":273},[270,6713,6714],{},"// TankView.qml\n",[270,6716,6717],{"class":272,"line":279},[270,6718,6719],{},"Rectangle {\n",[270,6721,6722],{"class":272,"line":285},[270,6723,6724],{},"    width: 800\n",[270,6726,6727],{"class":272,"line":291},[270,6728,6729],{},"    height: 480\n",[270,6731,6732],{"class":272,"line":297},[270,6733,6734],{},"    color: \"#2C3E50\"\n",[270,6736,6737],{"class":272,"line":303},[270,6738,775],{"emptyLinePlaceholder":524},[270,6740,6741],{"class":272,"line":515},[270,6742,6743],{},"    property int tankId: 1\n",[270,6745,6746],{"class":272,"line":793},[270,6747,6748],{},"    property real weight: 0.0\n",[270,6750,6751],{"class":272,"line":799},[270,6752,6753],{},"    property real capacity: 5000.0\n",[270,6755,6756],{"class":272,"line":805},[270,6757,6758],{},"    property real fillPercent: (weight / capacity) * 100\n",[270,6760,6761],{"class":272,"line":2120},[270,6762,775],{"emptyLinePlaceholder":524},[270,6764,6765],{"class":272,"line":2126},[270,6766,5719],{},[270,6768,6769],{"class":272,"line":2132},[270,6770,5687],{},[270,6772,6773],{"class":272,"line":3375},[270,6774,6775],{},"        anchors.margins: 20\n",[270,6777,6778],{"class":272,"line":3381},[270,6779,775],{"emptyLinePlaceholder":524},[270,6781,6782],{"class":272,"line":3387},[270,6783,6784],{},"        // Tank visualization\n",[270,6786,6787],{"class":272,"line":3393},[270,6788,5786],{},[270,6790,6791],{"class":272,"line":3399},[270,6792,6793],{},"            Layout.fillWidth: true\n",[270,6795,6796],{"class":272,"line":3405},[270,6797,6798],{},"            Layout.preferredHeight: 300\n",[270,6800,6801],{"class":272,"line":3411},[270,6802,6803],{},"            color: \"transparent\"\n",[270,6805,6806],{"class":272,"line":3417},[270,6807,6808],{},"            border.color: \"#ECF0F1\"\n",[270,6810,6811],{"class":272,"line":3423},[270,6812,6813],{},"            border.width: 3\n",[270,6815,6816],{"class":272,"line":3429},[270,6817,775],{"emptyLinePlaceholder":524},[270,6819,6820],{"class":272,"line":3434},[270,6821,6822],{},"            // Fill level\n",[270,6824,6825],{"class":272,"line":3440},[270,6826,6827],{},"            Rectangle {\n",[270,6829,6830],{"class":272,"line":3446},[270,6831,6832],{},"                anchors.bottom: parent.bottom\n",[270,6834,6835],{"class":272,"line":3452},[270,6836,6837],{},"                anchors.left: parent.left\n",[270,6839,6840],{"class":272,"line":3457},[270,6841,6842],{},"                anchors.right: parent.right\n",[270,6844,6845],{"class":272,"line":3463},[270,6846,6847],{},"                height: parent.height * (fillPercent / 100)\n",[270,6849,6850],{"class":272,"line":3469},[270,6851,6852],{},"                color: fillPercent > 90 ? \"#E74C3C\" : \"#3498DB\"\n",[270,6854,6855],{"class":272,"line":3475},[270,6856,775],{"emptyLinePlaceholder":524},[270,6858,6859],{"class":272,"line":3480},[270,6860,6861],{},"                Behavior on height {\n",[270,6863,6864],{"class":272,"line":3486},[270,6865,6866],{},"                    NumberAnimation { duration: 300 }\n",[270,6868,6869],{"class":272,"line":3492},[270,6870,3672],{},[270,6872,6873],{"class":272,"line":3497},[270,6874,4592],{},[270,6876,6877],{"class":272,"line":3503},[270,6878,775],{"emptyLinePlaceholder":524},[270,6880,6881],{"class":272,"line":3509},[270,6882,6883],{},"            // Weight text\n",[270,6885,6886],{"class":272,"line":3515},[270,6887,5815],{},[270,6889,6890],{"class":272,"line":3521},[270,6891,5820],{},[270,6893,6894],{"class":272,"line":3527},[270,6895,6896],{},"                text: weight.toFixed(1) + \" kg\"\n",[270,6898,6899],{"class":272,"line":3532},[270,6900,6901],{},"                font.pixelSize: 64\n",[270,6903,6904],{"class":272,"line":3538},[270,6905,5835],{},[270,6907,6908],{"class":272,"line":3544},[270,6909,5840],{},[270,6911,6912],{"class":272,"line":3550},[270,6913,4592],{},[270,6915,6916],{"class":272,"line":3556},[270,6917,4491],{},[270,6919,6920],{"class":272,"line":3562},[270,6921,775],{"emptyLinePlaceholder":524},[270,6923,6924],{"class":272,"line":3568},[270,6925,6926],{},"        // Percentage bar\n",[270,6928,6929],{"class":272,"line":3574},[270,6930,6931],{},"        ProgressBar {\n",[270,6933,6934],{"class":272,"line":3580},[270,6935,6793],{},[270,6937,6938],{"class":272,"line":3586},[270,6939,6940],{},"            value: fillPercent / 100\n",[270,6942,6943],{"class":272,"line":3592},[270,6944,775],{"emptyLinePlaceholder":524},[270,6946,6947],{"class":272,"line":3597},[270,6948,6949],{},"            background: Rectangle {\n",[270,6951,6952],{"class":272,"line":3603},[270,6953,6954],{},"                color: \"#34495E\"\n",[270,6956,6957],{"class":272,"line":3609},[270,6958,6959],{},"                radius: 5\n",[270,6961,6962],{"class":272,"line":3615},[270,6963,4592],{},[270,6965,6966],{"class":272,"line":3621},[270,6967,775],{"emptyLinePlaceholder":524},[270,6969,6970],{"class":272,"line":3627},[270,6971,6972],{},"            contentItem: Item {\n",[270,6974,6975],{"class":272,"line":3633},[270,6976,6977],{},"                Rectangle {\n",[270,6979,6980],{"class":272,"line":3639},[270,6981,6982],{},"                    width: parent.width * parent.parent.value\n",[270,6984,6985],{"class":272,"line":3645},[270,6986,6987],{},"                    height: parent.height\n",[270,6989,6990],{"class":272,"line":3651},[270,6991,6992],{},"                    color: parent.parent.value > 0.9 ? \"#E74C3C\" : \"#2ECC71\"\n",[270,6994,6995],{"class":272,"line":3657},[270,6996,6997],{},"                    radius: 5\n",[270,6999,7000],{"class":272,"line":3663},[270,7001,3672],{},[270,7003,7004],{"class":272,"line":3669},[270,7005,4592],{},[270,7007,7008],{"class":272,"line":3675},[270,7009,4491],{},[270,7011,7012],{"class":272,"line":3681},[270,7013,775],{"emptyLinePlaceholder":524},[270,7015,7016],{"class":272,"line":3687},[270,7017,5743],{},[270,7019,7020],{"class":272,"line":3693},[270,7021,7022],{},"            text: fillPercent.toFixed(1) + \"% Full\"\n",[270,7024,7025],{"class":272,"line":3698},[270,7026,7027],{},"            font.pixelSize: 24\n",[270,7029,7030],{"class":272,"line":3704},[270,7031,5763],{},[270,7033,7034],{"class":272,"line":3710},[270,7035,5768],{},[270,7037,7038],{"class":272,"line":3716},[270,7039,4491],{},[270,7041,7042],{"class":272,"line":3721},[270,7043,3795],{},[270,7045,7046],{"class":272,"line":3727},[270,7047,2129],{},[24,7049,7051],{"id":7050},"gateway-application-python","Gateway Application (Python)",[16,7053,7054],{},[93,7055,7056],{},"Main Gateway Logic:",[29,7058,7060],{"className":751,"code":7059,"language":753,"meta":38,"style":38},"#!/usr/bin/env python3\nimport json\nimport time\nfrom datetime import datetime\nfrom pymodbus.client.sync import ModbusTcpClient\nfrom awsiot import mqtt_connection_builder\nimport sqlite3\n\nclass MilkTankGateway:\n    def __init__(self):\n        self.tanks = [\n            {\"id\": 1, \"name\": \"Tank-1\", \"zma_ip\": \"192.168.1.101\"},\n            {\"id\": 2, \"name\": \"Tank-2\", \"zma_ip\": \"192.168.1.102\"},\n            {\"id\": 3, \"name\": \"Tank-3\", \"zma_ip\": \"192.168.1.103\"},\n        ]\n\n        # Modbus clients\n        self.modbus_clients = {}\n        for tank in self.tanks:\n            client = ModbusTcpClient(tank['zma_ip'], port=502)\n            client.connect()\n            self.modbus_clients[tank['id']] = client\n\n        # AWS MQTT connection\n        self.mqtt_connection = self._setup_aws_mqtt()\n\n        # Local database backup\n        self.db = sqlite3.connect('/data/milk_tanks.db')\n        self._init_database()\n\n    def _setup_aws_mqtt(self):\n        \"\"\"Setup AWS IoT Core MQTT connection\"\"\"\n        return mqtt_connection_builder.mtls_from_path(\n            endpoint=\"xxxxx.iot.eu-west-1.amazonaws.com\",\n            port=8883,\n            cert_filepath=\"/certs/gateway-cert.pem\",\n            pri_key_filepath=\"/certs/gateway-private.key\",\n            ca_filepath=\"/certs/AmazonRootCA1.pem\",\n            client_id=\"milk-facility-gateway\",\n            clean_session=False,\n            keep_alive_secs=30\n        )\n\n    def read_tank_weight(self, tank_id):\n        \"\"\"Read weight from ZMA-4 via Modbus\"\"\"\n        client = self.modbus_clients[tank_id]\n\n        # Read holding registers 200-203 (Total weight + Tare)\n        result = client.read_holding_registers(200, 4, unit=1)\n\n        if not result.isError():\n            gross = self._registers_to_float(result.registers[0:2])\n            net = self._registers_to_float(result.registers[2:4])\n            tare = self._registers_to_float(result.registers[4:6])\n\n            return {\n                \"tank_id\": tank_id,\n                \"timestamp\": datetime.utcnow().isoformat() + \"Z\",\n                \"gross_weight\": round(gross, 2),\n                \"net_weight\": round(net, 2),\n                \"tare_weight\": round(tare, 2),\n                \"fill_percent\": round((net / 5000.0) * 100, 1)\n            }\n\n        return None\n\n    def _registers_to_float(self, registers):\n        \"\"\"Convert 2 Modbus registers to Float32\"\"\"\n        import struct\n        raw = (registers[0] \u003C\u003C 16) | registers[1]\n        return struct.unpack('f', struct.pack('I', raw))[0]\n\n    def publish_to_aws(self, data):\n        \"\"\"Publish data to AWS IoT Core\"\"\"\n        topic = f\"amazeng/milk-facility/tank/{data['tank_id']}/data\"\n        payload = json.dumps(data)\n\n        self.mqtt_connection.publish(\n            topic=topic,\n            payload=payload,\n            qos=1\n        )\n\n        print(f\"→ AWS: {topic} | {data['net_weight']} kg\")\n\n    def save_local_backup(self, data):\n        \"\"\"Save data to local SQLite database\"\"\"\n        cursor = self.db.cursor()\n        cursor.execute(\"\"\"\n            INSERT INTO tank_data (tank_id, timestamp, net_weight, fill_percent)\n            VALUES (?, ?, ?, ?)\n        \"\"\", (data['tank_id'], data['timestamp'],\n              data['net_weight'], data['fill_percent']))\n        self.db.commit()\n\n    def run(self):\n        \"\"\"Main loop: Read → Publish → Store\"\"\"\n        print(\"🚀 Milk Tank Gateway started\")\n\n        try:\n            while True:\n                for tank in self.tanks:\n                    # Read from GDT\n                    data = self.read_tank_weight(tank['id'])\n\n                    if data:\n                        # Send to AWS\n                        self.publish_to_aws(data)\n\n                        # Local backup\n                        self.save_local_backup(data)\n\n                time.sleep(1)  # 1 second polling interval\n\n        except KeyboardInterrupt:\n            print(\"\\n✋ Gateway stopped\")\n            self.shutdown()\n\nif __name__ == \"__main__\":\n    gateway = MilkTankGateway()\n    gateway.run()\n",[36,7061,7062,7067,7071,7076,7081,7086,7091,7096,7100,7105,7110,7115,7120,7125,7130,7135,7139,7144,7149,7154,7159,7164,7169,7173,7178,7183,7187,7192,7197,7202,7206,7211,7216,7221,7226,7231,7236,7241,7246,7251,7256,7261,7265,7269,7274,7279,7284,7288,7293,7298,7302,7307,7312,7317,7322,7326,7331,7336,7341,7346,7351,7356,7361,7365,7369,7374,7378,7383,7388,7393,7398,7403,7407,7412,7417,7422,7427,7431,7436,7441,7446,7451,7455,7459,7464,7468,7474,7480,7486,7492,7498,7504,7510,7516,7522,7527,7533,7539,7545,7550,7556,7562,7568,7574,7580,7585,7591,7597,7603,7608,7614,7620,7625,7631,7636,7642,7648,7654,7659,7665,7671],{"__ignoreMap":38},[270,7063,7064],{"class":272,"line":273},[270,7065,7066],{},"#!/usr/bin/env python3\n",[270,7068,7069],{"class":272,"line":279},[270,7070,3319],{},[270,7072,7073],{"class":272,"line":285},[270,7074,7075],{},"import time\n",[270,7077,7078],{"class":272,"line":291},[270,7079,7080],{},"from datetime import datetime\n",[270,7082,7083],{"class":272,"line":297},[270,7084,7085],{},"from pymodbus.client.sync import ModbusTcpClient\n",[270,7087,7088],{"class":272,"line":303},[270,7089,7090],{},"from awsiot import mqtt_connection_builder\n",[270,7092,7093],{"class":272,"line":515},[270,7094,7095],{},"import sqlite3\n",[270,7097,7098],{"class":272,"line":793},[270,7099,775],{"emptyLinePlaceholder":524},[270,7101,7102],{"class":272,"line":799},[270,7103,7104],{},"class MilkTankGateway:\n",[270,7106,7107],{"class":272,"line":805},[270,7108,7109],{},"    def __init__(self):\n",[270,7111,7112],{"class":272,"line":2120},[270,7113,7114],{},"        self.tanks = [\n",[270,7116,7117],{"class":272,"line":2126},[270,7118,7119],{},"            {\"id\": 1, \"name\": \"Tank-1\", \"zma_ip\": \"192.168.1.101\"},\n",[270,7121,7122],{"class":272,"line":2132},[270,7123,7124],{},"            {\"id\": 2, \"name\": \"Tank-2\", \"zma_ip\": \"192.168.1.102\"},\n",[270,7126,7127],{"class":272,"line":3375},[270,7128,7129],{},"            {\"id\": 3, \"name\": \"Tank-3\", \"zma_ip\": \"192.168.1.103\"},\n",[270,7131,7132],{"class":272,"line":3381},[270,7133,7134],{},"        ]\n",[270,7136,7137],{"class":272,"line":3387},[270,7138,775],{"emptyLinePlaceholder":524},[270,7140,7141],{"class":272,"line":3393},[270,7142,7143],{},"        # Modbus clients\n",[270,7145,7146],{"class":272,"line":3399},[270,7147,7148],{},"        self.modbus_clients = {}\n",[270,7150,7151],{"class":272,"line":3405},[270,7152,7153],{},"        for tank in self.tanks:\n",[270,7155,7156],{"class":272,"line":3411},[270,7157,7158],{},"            client = ModbusTcpClient(tank['zma_ip'], port=502)\n",[270,7160,7161],{"class":272,"line":3417},[270,7162,7163],{},"            client.connect()\n",[270,7165,7166],{"class":272,"line":3423},[270,7167,7168],{},"            self.modbus_clients[tank['id']] = client\n",[270,7170,7171],{"class":272,"line":3429},[270,7172,775],{"emptyLinePlaceholder":524},[270,7174,7175],{"class":272,"line":3434},[270,7176,7177],{},"        # AWS MQTT connection\n",[270,7179,7180],{"class":272,"line":3440},[270,7181,7182],{},"        self.mqtt_connection = self._setup_aws_mqtt()\n",[270,7184,7185],{"class":272,"line":3446},[270,7186,775],{"emptyLinePlaceholder":524},[270,7188,7189],{"class":272,"line":3452},[270,7190,7191],{},"        # Local database backup\n",[270,7193,7194],{"class":272,"line":3457},[270,7195,7196],{},"        self.db = sqlite3.connect('/data/milk_tanks.db')\n",[270,7198,7199],{"class":272,"line":3463},[270,7200,7201],{},"        self._init_database()\n",[270,7203,7204],{"class":272,"line":3469},[270,7205,775],{"emptyLinePlaceholder":524},[270,7207,7208],{"class":272,"line":3475},[270,7209,7210],{},"    def _setup_aws_mqtt(self):\n",[270,7212,7213],{"class":272,"line":3480},[270,7214,7215],{},"        \"\"\"Setup AWS IoT Core MQTT connection\"\"\"\n",[270,7217,7218],{"class":272,"line":3486},[270,7219,7220],{},"        return mqtt_connection_builder.mtls_from_path(\n",[270,7222,7223],{"class":272,"line":3492},[270,7224,7225],{},"            endpoint=\"xxxxx.iot.eu-west-1.amazonaws.com\",\n",[270,7227,7228],{"class":272,"line":3497},[270,7229,7230],{},"            port=8883,\n",[270,7232,7233],{"class":272,"line":3503},[270,7234,7235],{},"            cert_filepath=\"/certs/gateway-cert.pem\",\n",[270,7237,7238],{"class":272,"line":3509},[270,7239,7240],{},"            pri_key_filepath=\"/certs/gateway-private.key\",\n",[270,7242,7243],{"class":272,"line":3515},[270,7244,7245],{},"            ca_filepath=\"/certs/AmazonRootCA1.pem\",\n",[270,7247,7248],{"class":272,"line":3521},[270,7249,7250],{},"            client_id=\"milk-facility-gateway\",\n",[270,7252,7253],{"class":272,"line":3527},[270,7254,7255],{},"            clean_session=False,\n",[270,7257,7258],{"class":272,"line":3532},[270,7259,7260],{},"            keep_alive_secs=30\n",[270,7262,7263],{"class":272,"line":3538},[270,7264,3766],{},[270,7266,7267],{"class":272,"line":3544},[270,7268,775],{"emptyLinePlaceholder":524},[270,7270,7271],{"class":272,"line":3550},[270,7272,7273],{},"    def read_tank_weight(self, tank_id):\n",[270,7275,7276],{"class":272,"line":3556},[270,7277,7278],{},"        \"\"\"Read weight from ZMA-4 via Modbus\"\"\"\n",[270,7280,7281],{"class":272,"line":3562},[270,7282,7283],{},"        client = self.modbus_clients[tank_id]\n",[270,7285,7286],{"class":272,"line":3568},[270,7287,775],{"emptyLinePlaceholder":524},[270,7289,7290],{"class":272,"line":3574},[270,7291,7292],{},"        # Read holding registers 200-203 (Total weight + Tare)\n",[270,7294,7295],{"class":272,"line":3580},[270,7296,7297],{},"        result = client.read_holding_registers(200, 4, unit=1)\n",[270,7299,7300],{"class":272,"line":3586},[270,7301,775],{"emptyLinePlaceholder":524},[270,7303,7304],{"class":272,"line":3592},[270,7305,7306],{},"        if not result.isError():\n",[270,7308,7309],{"class":272,"line":3597},[270,7310,7311],{},"            gross = self._registers_to_float(result.registers[0:2])\n",[270,7313,7314],{"class":272,"line":3603},[270,7315,7316],{},"            net = self._registers_to_float(result.registers[2:4])\n",[270,7318,7319],{"class":272,"line":3609},[270,7320,7321],{},"            tare = self._registers_to_float(result.registers[4:6])\n",[270,7323,7324],{"class":272,"line":3615},[270,7325,775],{"emptyLinePlaceholder":524},[270,7327,7328],{"class":272,"line":3621},[270,7329,7330],{},"            return {\n",[270,7332,7333],{"class":272,"line":3627},[270,7334,7335],{},"                \"tank_id\": tank_id,\n",[270,7337,7338],{"class":272,"line":3633},[270,7339,7340],{},"                \"timestamp\": datetime.utcnow().isoformat() + \"Z\",\n",[270,7342,7343],{"class":272,"line":3639},[270,7344,7345],{},"                \"gross_weight\": round(gross, 2),\n",[270,7347,7348],{"class":272,"line":3645},[270,7349,7350],{},"                \"net_weight\": round(net, 2),\n",[270,7352,7353],{"class":272,"line":3651},[270,7354,7355],{},"                \"tare_weight\": round(tare, 2),\n",[270,7357,7358],{"class":272,"line":3657},[270,7359,7360],{},"                \"fill_percent\": round((net / 5000.0) * 100, 1)\n",[270,7362,7363],{"class":272,"line":3663},[270,7364,4592],{},[270,7366,7367],{"class":272,"line":3669},[270,7368,775],{"emptyLinePlaceholder":524},[270,7370,7371],{"class":272,"line":3675},[270,7372,7373],{},"        return None\n",[270,7375,7376],{"class":272,"line":3681},[270,7377,775],{"emptyLinePlaceholder":524},[270,7379,7380],{"class":272,"line":3687},[270,7381,7382],{},"    def _registers_to_float(self, registers):\n",[270,7384,7385],{"class":272,"line":3693},[270,7386,7387],{},"        \"\"\"Convert 2 Modbus registers to Float32\"\"\"\n",[270,7389,7390],{"class":272,"line":3698},[270,7391,7392],{},"        import struct\n",[270,7394,7395],{"class":272,"line":3704},[270,7396,7397],{},"        raw = (registers[0] \u003C\u003C 16) | registers[1]\n",[270,7399,7400],{"class":272,"line":3710},[270,7401,7402],{},"        return struct.unpack('f', struct.pack('I', raw))[0]\n",[270,7404,7405],{"class":272,"line":3716},[270,7406,775],{"emptyLinePlaceholder":524},[270,7408,7409],{"class":272,"line":3721},[270,7410,7411],{},"    def publish_to_aws(self, data):\n",[270,7413,7414],{"class":272,"line":3727},[270,7415,7416],{},"        \"\"\"Publish data to AWS IoT Core\"\"\"\n",[270,7418,7419],{"class":272,"line":3733},[270,7420,7421],{},"        topic = f\"amazeng/milk-facility/tank/{data['tank_id']}/data\"\n",[270,7423,7424],{"class":272,"line":3739},[270,7425,7426],{},"        payload = json.dumps(data)\n",[270,7428,7429],{"class":272,"line":3745},[270,7430,775],{"emptyLinePlaceholder":524},[270,7432,7433],{"class":272,"line":3751},[270,7434,7435],{},"        self.mqtt_connection.publish(\n",[270,7437,7438],{"class":272,"line":3757},[270,7439,7440],{},"            topic=topic,\n",[270,7442,7443],{"class":272,"line":3763},[270,7444,7445],{},"            payload=payload,\n",[270,7447,7448],{"class":272,"line":3769},[270,7449,7450],{},"            qos=1\n",[270,7452,7453],{"class":272,"line":3774},[270,7454,3766],{},[270,7456,7457],{"class":272,"line":3780},[270,7458,775],{"emptyLinePlaceholder":524},[270,7460,7461],{"class":272,"line":3786},[270,7462,7463],{},"        print(f\"→ AWS: {topic} | {data['net_weight']} kg\")\n",[270,7465,7466],{"class":272,"line":3792},[270,7467,775],{"emptyLinePlaceholder":524},[270,7469,7471],{"class":272,"line":7470},86,[270,7472,7473],{},"    def save_local_backup(self, data):\n",[270,7475,7477],{"class":272,"line":7476},87,[270,7478,7479],{},"        \"\"\"Save data to local SQLite database\"\"\"\n",[270,7481,7483],{"class":272,"line":7482},88,[270,7484,7485],{},"        cursor = self.db.cursor()\n",[270,7487,7489],{"class":272,"line":7488},89,[270,7490,7491],{},"        cursor.execute(\"\"\"\n",[270,7493,7495],{"class":272,"line":7494},90,[270,7496,7497],{},"            INSERT INTO tank_data (tank_id, timestamp, net_weight, fill_percent)\n",[270,7499,7501],{"class":272,"line":7500},91,[270,7502,7503],{},"            VALUES (?, ?, ?, ?)\n",[270,7505,7507],{"class":272,"line":7506},92,[270,7508,7509],{},"        \"\"\", (data['tank_id'], data['timestamp'],\n",[270,7511,7513],{"class":272,"line":7512},93,[270,7514,7515],{},"              data['net_weight'], data['fill_percent']))\n",[270,7517,7519],{"class":272,"line":7518},94,[270,7520,7521],{},"        self.db.commit()\n",[270,7523,7525],{"class":272,"line":7524},95,[270,7526,775],{"emptyLinePlaceholder":524},[270,7528,7530],{"class":272,"line":7529},96,[270,7531,7532],{},"    def run(self):\n",[270,7534,7536],{"class":272,"line":7535},97,[270,7537,7538],{},"        \"\"\"Main loop: Read → Publish → Store\"\"\"\n",[270,7540,7542],{"class":272,"line":7541},98,[270,7543,7544],{},"        print(\"🚀 Milk Tank Gateway started\")\n",[270,7546,7548],{"class":272,"line":7547},99,[270,7549,775],{"emptyLinePlaceholder":524},[270,7551,7553],{"class":272,"line":7552},100,[270,7554,7555],{},"        try:\n",[270,7557,7559],{"class":272,"line":7558},101,[270,7560,7561],{},"            while True:\n",[270,7563,7565],{"class":272,"line":7564},102,[270,7566,7567],{},"                for tank in self.tanks:\n",[270,7569,7571],{"class":272,"line":7570},103,[270,7572,7573],{},"                    # Read from GDT\n",[270,7575,7577],{"class":272,"line":7576},104,[270,7578,7579],{},"                    data = self.read_tank_weight(tank['id'])\n",[270,7581,7583],{"class":272,"line":7582},105,[270,7584,775],{"emptyLinePlaceholder":524},[270,7586,7588],{"class":272,"line":7587},106,[270,7589,7590],{},"                    if data:\n",[270,7592,7594],{"class":272,"line":7593},107,[270,7595,7596],{},"                        # Send to AWS\n",[270,7598,7600],{"class":272,"line":7599},108,[270,7601,7602],{},"                        self.publish_to_aws(data)\n",[270,7604,7606],{"class":272,"line":7605},109,[270,7607,775],{"emptyLinePlaceholder":524},[270,7609,7611],{"class":272,"line":7610},110,[270,7612,7613],{},"                        # Local backup\n",[270,7615,7617],{"class":272,"line":7616},111,[270,7618,7619],{},"                        self.save_local_backup(data)\n",[270,7621,7623],{"class":272,"line":7622},112,[270,7624,775],{"emptyLinePlaceholder":524},[270,7626,7628],{"class":272,"line":7627},113,[270,7629,7630],{},"                time.sleep(1)  # 1 second polling interval\n",[270,7632,7634],{"class":272,"line":7633},114,[270,7635,775],{"emptyLinePlaceholder":524},[270,7637,7639],{"class":272,"line":7638},115,[270,7640,7641],{},"        except KeyboardInterrupt:\n",[270,7643,7645],{"class":272,"line":7644},116,[270,7646,7647],{},"            print(\"\\n✋ Gateway stopped\")\n",[270,7649,7651],{"class":272,"line":7650},117,[270,7652,7653],{},"            self.shutdown()\n",[270,7655,7657],{"class":272,"line":7656},118,[270,7658,775],{"emptyLinePlaceholder":524},[270,7660,7662],{"class":272,"line":7661},119,[270,7663,7664],{},"if __name__ == \"__main__\":\n",[270,7666,7668],{"class":272,"line":7667},120,[270,7669,7670],{},"    gateway = MilkTankGateway()\n",[270,7672,7674],{"class":272,"line":7673},121,[270,7675,7676],{},"    gateway.run()\n",[11,7678,7680],{"id":7679},"aws-iot-rules-and-alarms","AWS IoT Rules and Alarms",[24,7682,7684],{"id":7683},"high-capacity-alarm-90","High Capacity Alarm (>90%)",[16,7686,7687],{},[93,7688,7689],{},"IoT Rule:",[29,7691,7693],{"className":1819,"code":7692,"language":1821,"meta":38,"style":38},"SELECT\n  tank_id,\n  fill_percent,\n  timestamp\nFROM\n  'amazeng/milk-facility/tank/+/data'\nWHERE\n  fill_percent > 90\n",[36,7694,7695,7700,7705,7710,7715,7720,7725,7730],{"__ignoreMap":38},[270,7696,7697],{"class":272,"line":273},[270,7698,7699],{},"SELECT\n",[270,7701,7702],{"class":272,"line":279},[270,7703,7704],{},"  tank_id,\n",[270,7706,7707],{"class":272,"line":285},[270,7708,7709],{},"  fill_percent,\n",[270,7711,7712],{"class":272,"line":291},[270,7713,7714],{},"  timestamp\n",[270,7716,7717],{"class":272,"line":297},[270,7718,7719],{},"FROM\n",[270,7721,7722],{"class":272,"line":303},[270,7723,7724],{},"  'amazeng/milk-facility/tank/+/data'\n",[270,7726,7727],{"class":272,"line":515},[270,7728,7729],{},"WHERE\n",[270,7731,7732],{"class":272,"line":793},[270,7733,7734],{},"  fill_percent > 90\n",[16,7736,7737,7740],{},[93,7738,7739],{},"Action:"," Trigger SNS (SMS + Email)",[16,7742,7743],{},[93,7744,7745],{},"Lambda Function:",[29,7747,7749],{"className":751,"code":7748,"language":753,"meta":38,"style":38},"import boto3\n\nsns = boto3.client('sns')\n\ndef lambda_handler(event, context):\n    tank_id = event['tank_id']\n    fill_percent = event['fill_percent']\n\n    message = f\"\"\"\n    ⚠️ TANK CAPACITY WARNING\n\n    Tank: {tank_id}\n    Fill Level: {fill_percent}%\n    Time: {event['timestamp']}\n\n    Action Required: Prepare for milk collection\n    \"\"\"\n\n    sns.publish(\n        TopicArn='arn:aws:sns:eu-west-1:xxx:milk-tank-alarms',\n        Subject='Tank Capacity Alert',\n        Message=message\n    )\n\n    return {'status': 'alarm_sent'}\n",[36,7750,7751,7755,7759,7764,7768,7772,7776,7781,7785,7790,7795,7799,7804,7809,7814,7818,7823,7827,7831,7836,7841,7846,7851,7855,7859],{"__ignoreMap":38},[270,7752,7753],{"class":272,"line":273},[270,7754,3314],{},[270,7756,7757],{"class":272,"line":279},[270,7758,775],{"emptyLinePlaceholder":524},[270,7760,7761],{"class":272,"line":285},[270,7762,7763],{},"sns = boto3.client('sns')\n",[270,7765,7766],{"class":272,"line":291},[270,7767,775],{"emptyLinePlaceholder":524},[270,7769,7770],{"class":272,"line":297},[270,7771,3347],{},[270,7773,7774],{"class":272,"line":303},[270,7775,3357],{},[270,7777,7778],{"class":272,"line":515},[270,7779,7780],{},"    fill_percent = event['fill_percent']\n",[270,7782,7783],{"class":272,"line":793},[270,7784,775],{"emptyLinePlaceholder":524},[270,7786,7787],{"class":272,"line":799},[270,7788,7789],{},"    message = f\"\"\"\n",[270,7791,7792],{"class":272,"line":805},[270,7793,7794],{},"    ⚠️ TANK CAPACITY WARNING\n",[270,7796,7797],{"class":272,"line":2120},[270,7798,775],{"emptyLinePlaceholder":524},[270,7800,7801],{"class":272,"line":2126},[270,7802,7803],{},"    Tank: {tank_id}\n",[270,7805,7806],{"class":272,"line":2132},[270,7807,7808],{},"    Fill Level: {fill_percent}%\n",[270,7810,7811],{"class":272,"line":3375},[270,7812,7813],{},"    Time: {event['timestamp']}\n",[270,7815,7816],{"class":272,"line":3381},[270,7817,775],{"emptyLinePlaceholder":524},[270,7819,7820],{"class":272,"line":3387},[270,7821,7822],{},"    Action Required: Prepare for milk collection\n",[270,7824,7825],{"class":272,"line":3393},[270,7826,3426],{},[270,7828,7829],{"class":272,"line":3399},[270,7830,775],{"emptyLinePlaceholder":524},[270,7832,7833],{"class":272,"line":3405},[270,7834,7835],{},"    sns.publish(\n",[270,7837,7838],{"class":272,"line":3411},[270,7839,7840],{},"        TopicArn='arn:aws:sns:eu-west-1:xxx:milk-tank-alarms',\n",[270,7842,7843],{"class":272,"line":3417},[270,7844,7845],{},"        Subject='Tank Capacity Alert',\n",[270,7847,7848],{"class":272,"line":3423},[270,7849,7850],{},"        Message=message\n",[270,7852,7853],{"class":272,"line":3429},[270,7854,3690],{},[270,7856,7857],{"class":272,"line":3434},[270,7858,775],{"emptyLinePlaceholder":524},[270,7860,7861],{"class":272,"line":3440},[270,7862,7863],{},"    return {'status': 'alarm_sent'}\n",[11,7865,444],{"id":443},[16,7867,7868],{},"This fully integrated solution demonstrates the power of Amazeng products working together:",[16,7870,5091,7871,7874,7875,5098,7877,7880,7881,5098,7883,7886,7887,5098,7889,7892,7893,5098,7895,7898,7899,5098,7901,7904],{},[93,7872,7873],{},"Real-time Monitoring:"," All tanks displayed with 1-second update rate",[2353,7876],{},[93,7878,7879],{},"High Precision:"," ZMA-4's 24-bit ADC per channel (±0.02%)",[2353,7882],{},[93,7884,7885],{},"Scalable:"," 4 channels per device, easy to add more tanks",[2353,7888],{},[93,7890,7891],{},"Cloud Integration:"," Historical data and analytics on AWS",[2353,7894],{},[93,7896,7897],{},"Alarm System:"," SMS/Email alerts for critical events",[2353,7900],{},[93,7902,7903],{},"Cost-Effective:"," 73% cheaper than traditional SCADA",[16,7906,7907],{},[93,7908,7909],{},"Product Selection Guide:",[40,7911,7912,7918],{},[43,7913,7914,7917],{},[93,7915,7916],{},"4 loadcells per tank:"," Use ZMA-4 (as shown in this article)",[43,7919,7920,7923,7924,7926],{},[93,7921,7922],{},"1-2 loadcells + DIO needed:"," Use ",[463,7925,471],{"href":1723}," (2 ch + 3 DIO)",[24,7928,7930],{"id":7929},"related-products-solutions","Related Products & Solutions",[40,7932,7933,7938,7943,7947,7951],{},[43,7934,7935,7937],{},[463,7936,466],{"href":1613}," - For 4-channel loadcell applications",[43,7939,7940,7942],{},[463,7941,471],{"href":1723}," - For 1-2 channel + DIO applications",[43,7944,7945],{},[463,7946,2465],{"href":2464},[43,7948,7949],{},[463,7950,2983],{"href":2634},[43,7952,7953],{},[463,7954,2382],{"href":2340},[477,7956,7957],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}",{"title":38,"searchDepth":279,"depth":279,"links":7959},[7960,7961,7965,7966,7971,7975,7978],{"id":13,"depth":279,"text":14},{"id":6196,"depth":279,"text":6197,"children":7962},[7963,7964],{"id":6200,"depth":285,"text":6201},{"id":6230,"depth":285,"text":6231},{"id":3279,"depth":279,"text":3280},{"id":6280,"depth":279,"text":6281,"children":7967},[7968,7969,7970],{"id":6284,"depth":285,"text":6285},{"id":6595,"depth":285,"text":6596},{"id":6652,"depth":285,"text":6653},{"id":6694,"depth":279,"text":6695,"children":7972},[7973,7974],{"id":6698,"depth":285,"text":6699},{"id":7050,"depth":285,"text":7051},{"id":7679,"depth":279,"text":7680,"children":7976},[7977],{"id":7683,"depth":285,"text":7684},{"id":443,"depth":279,"text":444,"children":7979},[7980],{"id":7929,"depth":285,"text":7930},"Real-world case study: Complete system architecture for 5-tank milk processing facility using ZMA, HMI and AWS IoT.",{"date":3011,"author":514,"readTime":3381,"featured":524,"tags":7983},[1360,518,7984,7985,7986,7987,7988],"AWS IoT","Industrial IoT","Full Stack","Case Study","Milk Tank",{"title":6162,"description":7981},"en/blog/fully-integrated-solution-zma-gdt-hmi-aws","oNAPJHhhUx_xIlmzIw5fzEJW-Z1YVZcwb0dz09jUNCY",{"id":7993,"title":7994,"body":7995,"description":10213,"extension":511,"meta":10214,"navigation":524,"path":10219,"seo":10220,"stem":10221,"__hash__":10222},"en_blog/en/blog/gdt-hmi-integration-modbus-weight-display.md","GDT + HMI Integration: Real-Time Weight Display with Modbus Communication",{"type":8,"value":7996,"toc":10196},[7997,7999,8022,8025,8027,8033,8037,8234,8238,8242,8249,8497,8504,9000,9004,9010,10010,10014,10016,10019,10024,10044,10048,10053,10106,10110,10121,10127,10130,10141,10143,10150,10173,10175,10194],[11,7998,14],{"id":13},[16,8000,8001,8002,467,8005,8008,8009,8011,8012,8014,8015,8017,8018,8021],{},"In industrial weighing systems, ",[93,8003,8004],{},"real-time weight display",[93,8006,8007],{},"recording"," are critical requirements. Our ",[463,8010,471],{"href":1723}," communicates with ",[463,8013,2465],{"href":2464}," via ",[93,8016,687],{}," or ",[93,8019,8020],{},"Modbus RTU"," protocol to meet these needs.",[16,8023,8024],{},"In this article, we examine in detail how to read, display, and record weight data from GDT on an HMI panel.",[11,8026,3280],{"id":3279},[29,8028,8031],{"className":8029,"code":8030,"language":34},[32],"┌──────────────────────────────────────────────────────┐\n│         Loadcell Platform (4-channel)                │\n│                                                      │\n│  ┌────────┐  ┌────────┐  ┌────────┐  ┌────────┐   │\n│  │LC #1   │  │LC #2   │  │LC #3   │  │LC #4   │   │\n│  │2mV/V   │  │2mV/V   │  │2mV/V   │  │2mV/V   │   │\n│  └───┬────┘  └───┬────┘  └───┬────┘  └───┬────┘   │\n│      │           │           │           │        │\n└──────┼───────────┼───────────┼───────────┼────────┘\n       │           │           │           │\n       └───────────┴───────────┴───────────┘\n                     │\n              ┌──────▼──────┐\n              │  GDT-410M   │  ← 24-bit ADC, Modbus TCP\n              │  Transmitter│\n              └──────┬──────┘\n                     │ Ethernet (Modbus TCP)\n                     │ Port 502\n              ┌──────▼──────┐\n              │  HMI Panel  │  ← 10.1\" Touchscreen\n              │  Qt/QML UI  │     Embedded Linux\n              └─────────────┘\n",[36,8032,8030],{"__ignoreMap":38},[11,8034,8036],{"id":8035},"gdt-modbus-register-map","GDT Modbus Register Map",[636,8038,8039,8058],{},[639,8040,8041],{},[642,8042,8043,8046,8049,8052,8055],{},[645,8044,8045],{},"Register",[645,8047,8048],{},"Address",[645,8050,8051],{},"Type",[645,8053,8054],{},"Unit",[645,8056,8057],{},"Description",[655,8059,8060,8079,8096,8113,8131,8148,8165,8182,8200,8217],{},[642,8061,8062,8067,8070,8073,8076],{},[660,8063,8064],{},[93,8065,8066],{},"Gross Weight",[660,8068,8069],{},"40001-40002",[660,8071,8072],{},"Float32",[660,8074,8075],{},"kg",[660,8077,8078],{},"Total weight (4 channels)",[642,8080,8081,8086,8089,8091,8093],{},[660,8082,8083],{},[93,8084,8085],{},"Net Weight",[660,8087,8088],{},"40003-40004",[660,8090,8072],{},[660,8092,8075],{},[660,8094,8095],{},"Gross - Tare",[642,8097,8098,8103,8106,8108,8110],{},[660,8099,8100],{},[93,8101,8102],{},"Tare Value",[660,8104,8105],{},"40005-40006",[660,8107,8072],{},[660,8109,8075],{},[660,8111,8112],{},"Container weight",[642,8114,8115,8120,8123,8125,8128],{},[660,8116,8117],{},[93,8118,8119],{},"Channel 1",[660,8121,8122],{},"40011-40012",[660,8124,8072],{},[660,8126,8127],{},"mV/V",[660,8129,8130],{},"Loadcell 1 raw data",[642,8132,8133,8138,8141,8143,8145],{},[660,8134,8135],{},[93,8136,8137],{},"Channel 2",[660,8139,8140],{},"40013-40014",[660,8142,8072],{},[660,8144,8127],{},[660,8146,8147],{},"Loadcell 2 raw data",[642,8149,8150,8155,8158,8160,8162],{},[660,8151,8152],{},[93,8153,8154],{},"Channel 3",[660,8156,8157],{},"40015-40016",[660,8159,8072],{},[660,8161,8127],{},[660,8163,8164],{},"Loadcell 3 raw data",[642,8166,8167,8172,8175,8177,8179],{},[660,8168,8169],{},[93,8170,8171],{},"Channel 4",[660,8173,8174],{},"40017-40018",[660,8176,8072],{},[660,8178,8127],{},[660,8180,8181],{},"Loadcell 4 raw data",[642,8183,8184,8189,8192,8195,8197],{},[660,8185,8186],{},[93,8187,8188],{},"Status",[660,8190,8191],{},"40101",[660,8193,8194],{},"Uint16",[660,8196,3143],{},[660,8198,8199],{},"Device status",[642,8201,8202,8207,8210,8212,8214],{},[660,8203,8204],{},[93,8205,8206],{},"Zero Command",[660,8208,8209],{},"40201",[660,8211,8194],{},[660,8213,3143],{},[660,8215,8216],{},"Write 1 = Zero",[642,8218,8219,8224,8227,8229,8231],{},[660,8220,8221],{},[93,8222,8223],{},"Tare Command",[660,8225,8226],{},"40202",[660,8228,8194],{},[660,8230,3143],{},[660,8232,8233],{},"Write 1 = Tare",[11,8235,8237],{"id":8236},"hmi-application-qt-qml-interface","HMI Application: Qt + QML Interface",[24,8239,8241],{"id":8240},"c-modbus-backend","C++ Modbus Backend",[16,8243,8244],{},[93,8245,8246],{},[36,8247,8248],{},"ModbusReader.h",[29,8250,8252],{"className":264,"code":8251,"language":266,"meta":38,"style":38},"#ifndef MODBUSREADER_H\n#define MODBUSREADER_H\n\n#include \u003CQObject>\n#include \u003CQModbusTcpClient>\n#include \u003CQTimer>\n\nclass ModbusReader : public QObject\n{\n    Q_OBJECT\n    Q_PROPERTY(float grossWeight READ grossWeight NOTIFY weightChanged)\n    Q_PROPERTY(float netWeight READ netWeight NOTIFY weightChanged)\n    Q_PROPERTY(float tare READ tare NOTIFY weightChanged)\n    Q_PROPERTY(bool connected READ connected NOTIFY connectionChanged)\n\npublic:\n    explicit ModbusReader(QObject *parent = nullptr);\n    ~ModbusReader();\n\n    float grossWeight() const { return m_grossWeight; }\n    float netWeight() const { return m_netWeight; }\n    float tare() const { return m_tare; }\n    bool connected() const { return m_connected; }\n\n    Q_INVOKABLE void connectToDevice(const QString &ip, int port = 502);\n    Q_INVOKABLE void zero();\n    Q_INVOKABLE void setTare();\n\nsignals:\n    void weightChanged();\n    void connectionChanged();\n    void errorOccurred(const QString &error);\n\nprivate slots:\n    void onStateChanged(QModbusDevice::State state);\n    void onReadReady();\n    void readRegisters();\n\nprivate:\n    QModbusTcpClient *m_modbusClient;\n    QTimer *m_readTimer;\n\n    float m_grossWeight = 0.0f;\n    float m_netWeight = 0.0f;\n    float m_tare = 0.0f;\n    bool m_connected = false;\n\n    float registersToFloat(quint16 reg1, quint16 reg2);\n};\n\n#endif\n",[36,8253,8254,8259,8264,8268,8273,8278,8283,8287,8292,8296,8301,8306,8311,8316,8321,8325,8330,8335,8340,8344,8349,8354,8359,8364,8368,8373,8378,8383,8387,8392,8397,8402,8407,8411,8416,8421,8426,8431,8435,8440,8445,8450,8454,8459,8464,8469,8474,8478,8483,8488,8492],{"__ignoreMap":38},[270,8255,8256],{"class":272,"line":273},[270,8257,8258],{},"#ifndef MODBUSREADER_H\n",[270,8260,8261],{"class":272,"line":279},[270,8262,8263],{},"#define MODBUSREADER_H\n",[270,8265,8266],{"class":272,"line":285},[270,8267,775],{"emptyLinePlaceholder":524},[270,8269,8270],{"class":272,"line":291},[270,8271,8272],{},"#include \u003CQObject>\n",[270,8274,8275],{"class":272,"line":297},[270,8276,8277],{},"#include \u003CQModbusTcpClient>\n",[270,8279,8280],{"class":272,"line":303},[270,8281,8282],{},"#include \u003CQTimer>\n",[270,8284,8285],{"class":272,"line":515},[270,8286,775],{"emptyLinePlaceholder":524},[270,8288,8289],{"class":272,"line":793},[270,8290,8291],{},"class ModbusReader : public QObject\n",[270,8293,8294],{"class":272,"line":799},[270,8295,3812],{},[270,8297,8298],{"class":272,"line":805},[270,8299,8300],{},"    Q_OBJECT\n",[270,8302,8303],{"class":272,"line":2120},[270,8304,8305],{},"    Q_PROPERTY(float grossWeight READ grossWeight NOTIFY weightChanged)\n",[270,8307,8308],{"class":272,"line":2126},[270,8309,8310],{},"    Q_PROPERTY(float netWeight READ netWeight NOTIFY weightChanged)\n",[270,8312,8313],{"class":272,"line":2132},[270,8314,8315],{},"    Q_PROPERTY(float tare READ tare NOTIFY weightChanged)\n",[270,8317,8318],{"class":272,"line":3375},[270,8319,8320],{},"    Q_PROPERTY(bool connected READ connected NOTIFY connectionChanged)\n",[270,8322,8323],{"class":272,"line":3381},[270,8324,775],{"emptyLinePlaceholder":524},[270,8326,8327],{"class":272,"line":3387},[270,8328,8329],{},"public:\n",[270,8331,8332],{"class":272,"line":3393},[270,8333,8334],{},"    explicit ModbusReader(QObject *parent = nullptr);\n",[270,8336,8337],{"class":272,"line":3399},[270,8338,8339],{},"    ~ModbusReader();\n",[270,8341,8342],{"class":272,"line":3405},[270,8343,775],{"emptyLinePlaceholder":524},[270,8345,8346],{"class":272,"line":3411},[270,8347,8348],{},"    float grossWeight() const { return m_grossWeight; }\n",[270,8350,8351],{"class":272,"line":3417},[270,8352,8353],{},"    float netWeight() const { return m_netWeight; }\n",[270,8355,8356],{"class":272,"line":3423},[270,8357,8358],{},"    float tare() const { return m_tare; }\n",[270,8360,8361],{"class":272,"line":3429},[270,8362,8363],{},"    bool connected() const { return m_connected; }\n",[270,8365,8366],{"class":272,"line":3434},[270,8367,775],{"emptyLinePlaceholder":524},[270,8369,8370],{"class":272,"line":3440},[270,8371,8372],{},"    Q_INVOKABLE void connectToDevice(const QString &ip, int port = 502);\n",[270,8374,8375],{"class":272,"line":3446},[270,8376,8377],{},"    Q_INVOKABLE void zero();\n",[270,8379,8380],{"class":272,"line":3452},[270,8381,8382],{},"    Q_INVOKABLE void setTare();\n",[270,8384,8385],{"class":272,"line":3457},[270,8386,775],{"emptyLinePlaceholder":524},[270,8388,8389],{"class":272,"line":3463},[270,8390,8391],{},"signals:\n",[270,8393,8394],{"class":272,"line":3469},[270,8395,8396],{},"    void weightChanged();\n",[270,8398,8399],{"class":272,"line":3475},[270,8400,8401],{},"    void connectionChanged();\n",[270,8403,8404],{"class":272,"line":3480},[270,8405,8406],{},"    void errorOccurred(const QString &error);\n",[270,8408,8409],{"class":272,"line":3486},[270,8410,775],{"emptyLinePlaceholder":524},[270,8412,8413],{"class":272,"line":3492},[270,8414,8415],{},"private slots:\n",[270,8417,8418],{"class":272,"line":3497},[270,8419,8420],{},"    void onStateChanged(QModbusDevice::State state);\n",[270,8422,8423],{"class":272,"line":3503},[270,8424,8425],{},"    void onReadReady();\n",[270,8427,8428],{"class":272,"line":3509},[270,8429,8430],{},"    void readRegisters();\n",[270,8432,8433],{"class":272,"line":3515},[270,8434,775],{"emptyLinePlaceholder":524},[270,8436,8437],{"class":272,"line":3521},[270,8438,8439],{},"private:\n",[270,8441,8442],{"class":272,"line":3527},[270,8443,8444],{},"    QModbusTcpClient *m_modbusClient;\n",[270,8446,8447],{"class":272,"line":3532},[270,8448,8449],{},"    QTimer *m_readTimer;\n",[270,8451,8452],{"class":272,"line":3538},[270,8453,775],{"emptyLinePlaceholder":524},[270,8455,8456],{"class":272,"line":3544},[270,8457,8458],{},"    float m_grossWeight = 0.0f;\n",[270,8460,8461],{"class":272,"line":3550},[270,8462,8463],{},"    float m_netWeight = 0.0f;\n",[270,8465,8466],{"class":272,"line":3556},[270,8467,8468],{},"    float m_tare = 0.0f;\n",[270,8470,8471],{"class":272,"line":3562},[270,8472,8473],{},"    bool m_connected = false;\n",[270,8475,8476],{"class":272,"line":3568},[270,8477,775],{"emptyLinePlaceholder":524},[270,8479,8480],{"class":272,"line":3574},[270,8481,8482],{},"    float registersToFloat(quint16 reg1, quint16 reg2);\n",[270,8484,8485],{"class":272,"line":3580},[270,8486,8487],{},"};\n",[270,8489,8490],{"class":272,"line":3586},[270,8491,775],{"emptyLinePlaceholder":524},[270,8493,8494],{"class":272,"line":3592},[270,8495,8496],{},"#endif\n",[16,8498,8499],{},[93,8500,8501],{},[36,8502,8503],{},"ModbusReader.cpp",[29,8505,8507],{"className":264,"code":8506,"language":266,"meta":38,"style":38},"#include \"ModbusReader.h\"\n#include \u003CQModbusDataUnit>\n#include \u003CQDebug>\n\nModbusReader::ModbusReader(QObject *parent)\n    : QObject(parent)\n{\n    m_modbusClient = new QModbusTcpClient(this);\n\n    connect(m_modbusClient, &QModbusClient::stateChanged,\n            this, &ModbusReader::onStateChanged);\n\n    // Read every 200ms\n    m_readTimer = new QTimer(this);\n    connect(m_readTimer, &QTimer::timeout, this, &ModbusReader::readRegisters);\n}\n\nvoid ModbusReader::connectToDevice(const QString &ip, int port)\n{\n    m_modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ip);\n    m_modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);\n    m_modbusClient->setTimeout(1000);\n    m_modbusClient->setNumberOfRetries(3);\n\n    m_modbusClient->connectDevice();\n}\n\nvoid ModbusReader::onStateChanged(QModbusDevice::State state)\n{\n    m_connected = (state == QModbusDevice::ConnectedState);\n    emit connectionChanged();\n\n    if (m_connected) {\n        qDebug() \u003C\u003C \"✓ Connected to GDT\";\n        m_readTimer->start(200);  // 5 Hz update rate\n    } else {\n        m_readTimer->stop();\n    }\n}\n\nvoid ModbusReader::readRegisters()\n{\n    if (!m_modbusClient || !m_connected) return;\n\n    // Read holding registers 40001-40006 (6 registers = 3 floats)\n    QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 6);\n\n    auto *reply = m_modbusClient->sendReadRequest(readUnit, 1);  // Unit ID = 1\n\n    if (reply) {\n        if (!reply->isFinished()) {\n            connect(reply, &QModbusReply::finished, this, &ModbusReader::onReadReady);\n        } else {\n            delete reply;\n        }\n    }\n}\n\nvoid ModbusReader::onReadReady()\n{\n    auto *reply = qobject_cast\u003CQModbusReply *>(sender());\n    if (!reply) return;\n\n    if (reply->error() == QModbusDevice::NoError) {\n        const QModbusDataUnit unit = reply->result();\n\n        // Parse Float32 values (2 registers each)\n        m_grossWeight = registersToFloat(unit.value(0), unit.value(1));\n        m_netWeight = registersToFloat(unit.value(2), unit.value(3));\n        m_tare = registersToFloat(unit.value(4), unit.value(5));\n\n        emit weightChanged();\n    } else {\n        emit errorOccurred(reply->errorString());\n    }\n\n    reply->deleteLater();\n}\n\nfloat ModbusReader::registersToFloat(quint16 reg1, quint16 reg2)\n{\n    // IEEE 754 big-endian conversion\n    quint32 raw = (static_cast\u003Cquint32>(reg1) \u003C\u003C 16) | reg2;\n    float value;\n    memcpy(&value, &raw, sizeof(float));\n    return value;\n}\n\nvoid ModbusReader::zero()\n{\n    // Write 1 to register 40201\n    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 200, 1);\n    writeUnit.setValue(0, 1);\n\n    m_modbusClient->sendWriteRequest(writeUnit, 1);\n    qDebug() \u003C\u003C \"Zero command sent\";\n}\n\nvoid ModbusReader::setTare()\n{\n    // Write 1 to register 40202\n    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 201, 1);\n    writeUnit.setValue(0, 1);\n\n    m_modbusClient->sendWriteRequest(writeUnit, 1);\n    qDebug() \u003C\u003C \"Tare command sent\";\n}\n",[36,8508,8509,8514,8519,8524,8528,8533,8538,8542,8547,8551,8556,8561,8565,8570,8575,8580,8584,8588,8593,8597,8602,8607,8612,8617,8621,8626,8630,8634,8639,8643,8648,8653,8657,8662,8667,8672,8677,8682,8686,8690,8694,8699,8703,8708,8712,8717,8722,8726,8731,8735,8740,8745,8750,8755,8760,8764,8768,8772,8776,8781,8785,8790,8795,8799,8804,8809,8813,8818,8823,8828,8833,8837,8842,8846,8851,8855,8859,8864,8868,8872,8877,8881,8886,8891,8896,8901,8906,8910,8914,8919,8923,8928,8933,8938,8942,8947,8952,8956,8960,8965,8969,8974,8979,8983,8987,8991,8996],{"__ignoreMap":38},[270,8510,8511],{"class":272,"line":273},[270,8512,8513],{},"#include \"ModbusReader.h\"\n",[270,8515,8516],{"class":272,"line":279},[270,8517,8518],{},"#include \u003CQModbusDataUnit>\n",[270,8520,8521],{"class":272,"line":285},[270,8522,8523],{},"#include \u003CQDebug>\n",[270,8525,8526],{"class":272,"line":291},[270,8527,775],{"emptyLinePlaceholder":524},[270,8529,8530],{"class":272,"line":297},[270,8531,8532],{},"ModbusReader::ModbusReader(QObject *parent)\n",[270,8534,8535],{"class":272,"line":303},[270,8536,8537],{},"    : QObject(parent)\n",[270,8539,8540],{"class":272,"line":515},[270,8541,3812],{},[270,8543,8544],{"class":272,"line":793},[270,8545,8546],{},"    m_modbusClient = new QModbusTcpClient(this);\n",[270,8548,8549],{"class":272,"line":799},[270,8550,775],{"emptyLinePlaceholder":524},[270,8552,8553],{"class":272,"line":805},[270,8554,8555],{},"    connect(m_modbusClient, &QModbusClient::stateChanged,\n",[270,8557,8558],{"class":272,"line":2120},[270,8559,8560],{},"            this, &ModbusReader::onStateChanged);\n",[270,8562,8563],{"class":272,"line":2126},[270,8564,775],{"emptyLinePlaceholder":524},[270,8566,8567],{"class":272,"line":2132},[270,8568,8569],{},"    // Read every 200ms\n",[270,8571,8572],{"class":272,"line":3375},[270,8573,8574],{},"    m_readTimer = new QTimer(this);\n",[270,8576,8577],{"class":272,"line":3381},[270,8578,8579],{},"    connect(m_readTimer, &QTimer::timeout, this, &ModbusReader::readRegisters);\n",[270,8581,8582],{"class":272,"line":3387},[270,8583,2129],{},[270,8585,8586],{"class":272,"line":3393},[270,8587,775],{"emptyLinePlaceholder":524},[270,8589,8590],{"class":272,"line":3399},[270,8591,8592],{},"void ModbusReader::connectToDevice(const QString &ip, int port)\n",[270,8594,8595],{"class":272,"line":3405},[270,8596,3812],{},[270,8598,8599],{"class":272,"line":3411},[270,8600,8601],{},"    m_modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ip);\n",[270,8603,8604],{"class":272,"line":3417},[270,8605,8606],{},"    m_modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);\n",[270,8608,8609],{"class":272,"line":3423},[270,8610,8611],{},"    m_modbusClient->setTimeout(1000);\n",[270,8613,8614],{"class":272,"line":3429},[270,8615,8616],{},"    m_modbusClient->setNumberOfRetries(3);\n",[270,8618,8619],{"class":272,"line":3434},[270,8620,775],{"emptyLinePlaceholder":524},[270,8622,8623],{"class":272,"line":3440},[270,8624,8625],{},"    m_modbusClient->connectDevice();\n",[270,8627,8628],{"class":272,"line":3446},[270,8629,2129],{},[270,8631,8632],{"class":272,"line":3452},[270,8633,775],{"emptyLinePlaceholder":524},[270,8635,8636],{"class":272,"line":3457},[270,8637,8638],{},"void ModbusReader::onStateChanged(QModbusDevice::State state)\n",[270,8640,8641],{"class":272,"line":3463},[270,8642,3812],{},[270,8644,8645],{"class":272,"line":3469},[270,8646,8647],{},"    m_connected = (state == QModbusDevice::ConnectedState);\n",[270,8649,8650],{"class":272,"line":3475},[270,8651,8652],{},"    emit connectionChanged();\n",[270,8654,8655],{"class":272,"line":3480},[270,8656,775],{"emptyLinePlaceholder":524},[270,8658,8659],{"class":272,"line":3486},[270,8660,8661],{},"    if (m_connected) {\n",[270,8663,8664],{"class":272,"line":3492},[270,8665,8666],{},"        qDebug() \u003C\u003C \"✓ Connected to GDT\";\n",[270,8668,8669],{"class":272,"line":3497},[270,8670,8671],{},"        m_readTimer->start(200);  // 5 Hz update rate\n",[270,8673,8674],{"class":272,"line":3503},[270,8675,8676],{},"    } else {\n",[270,8678,8679],{"class":272,"line":3509},[270,8680,8681],{},"        m_readTimer->stop();\n",[270,8683,8684],{"class":272,"line":3515},[270,8685,3795],{},[270,8687,8688],{"class":272,"line":3521},[270,8689,2129],{},[270,8691,8692],{"class":272,"line":3527},[270,8693,775],{"emptyLinePlaceholder":524},[270,8695,8696],{"class":272,"line":3532},[270,8697,8698],{},"void ModbusReader::readRegisters()\n",[270,8700,8701],{"class":272,"line":3538},[270,8702,3812],{},[270,8704,8705],{"class":272,"line":3544},[270,8706,8707],{},"    if (!m_modbusClient || !m_connected) return;\n",[270,8709,8710],{"class":272,"line":3550},[270,8711,775],{"emptyLinePlaceholder":524},[270,8713,8714],{"class":272,"line":3556},[270,8715,8716],{},"    // Read holding registers 40001-40006 (6 registers = 3 floats)\n",[270,8718,8719],{"class":272,"line":3562},[270,8720,8721],{},"    QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 6);\n",[270,8723,8724],{"class":272,"line":3568},[270,8725,775],{"emptyLinePlaceholder":524},[270,8727,8728],{"class":272,"line":3574},[270,8729,8730],{},"    auto *reply = m_modbusClient->sendReadRequest(readUnit, 1);  // Unit ID = 1\n",[270,8732,8733],{"class":272,"line":3580},[270,8734,775],{"emptyLinePlaceholder":524},[270,8736,8737],{"class":272,"line":3586},[270,8738,8739],{},"    if (reply) {\n",[270,8741,8742],{"class":272,"line":3592},[270,8743,8744],{},"        if (!reply->isFinished()) {\n",[270,8746,8747],{"class":272,"line":3597},[270,8748,8749],{},"            connect(reply, &QModbusReply::finished, this, &ModbusReader::onReadReady);\n",[270,8751,8752],{"class":272,"line":3603},[270,8753,8754],{},"        } else {\n",[270,8756,8757],{"class":272,"line":3609},[270,8758,8759],{},"            delete reply;\n",[270,8761,8762],{"class":272,"line":3615},[270,8763,4491],{},[270,8765,8766],{"class":272,"line":3621},[270,8767,3795],{},[270,8769,8770],{"class":272,"line":3627},[270,8771,2129],{},[270,8773,8774],{"class":272,"line":3633},[270,8775,775],{"emptyLinePlaceholder":524},[270,8777,8778],{"class":272,"line":3639},[270,8779,8780],{},"void ModbusReader::onReadReady()\n",[270,8782,8783],{"class":272,"line":3645},[270,8784,3812],{},[270,8786,8787],{"class":272,"line":3651},[270,8788,8789],{},"    auto *reply = qobject_cast\u003CQModbusReply *>(sender());\n",[270,8791,8792],{"class":272,"line":3657},[270,8793,8794],{},"    if (!reply) return;\n",[270,8796,8797],{"class":272,"line":3663},[270,8798,775],{"emptyLinePlaceholder":524},[270,8800,8801],{"class":272,"line":3669},[270,8802,8803],{},"    if (reply->error() == QModbusDevice::NoError) {\n",[270,8805,8806],{"class":272,"line":3675},[270,8807,8808],{},"        const QModbusDataUnit unit = reply->result();\n",[270,8810,8811],{"class":272,"line":3681},[270,8812,775],{"emptyLinePlaceholder":524},[270,8814,8815],{"class":272,"line":3687},[270,8816,8817],{},"        // Parse Float32 values (2 registers each)\n",[270,8819,8820],{"class":272,"line":3693},[270,8821,8822],{},"        m_grossWeight = registersToFloat(unit.value(0), unit.value(1));\n",[270,8824,8825],{"class":272,"line":3698},[270,8826,8827],{},"        m_netWeight = registersToFloat(unit.value(2), unit.value(3));\n",[270,8829,8830],{"class":272,"line":3704},[270,8831,8832],{},"        m_tare = registersToFloat(unit.value(4), unit.value(5));\n",[270,8834,8835],{"class":272,"line":3710},[270,8836,775],{"emptyLinePlaceholder":524},[270,8838,8839],{"class":272,"line":3716},[270,8840,8841],{},"        emit weightChanged();\n",[270,8843,8844],{"class":272,"line":3721},[270,8845,8676],{},[270,8847,8848],{"class":272,"line":3727},[270,8849,8850],{},"        emit errorOccurred(reply->errorString());\n",[270,8852,8853],{"class":272,"line":3733},[270,8854,3795],{},[270,8856,8857],{"class":272,"line":3739},[270,8858,775],{"emptyLinePlaceholder":524},[270,8860,8861],{"class":272,"line":3745},[270,8862,8863],{},"    reply->deleteLater();\n",[270,8865,8866],{"class":272,"line":3751},[270,8867,2129],{},[270,8869,8870],{"class":272,"line":3757},[270,8871,775],{"emptyLinePlaceholder":524},[270,8873,8874],{"class":272,"line":3763},[270,8875,8876],{},"float ModbusReader::registersToFloat(quint16 reg1, quint16 reg2)\n",[270,8878,8879],{"class":272,"line":3769},[270,8880,3812],{},[270,8882,8883],{"class":272,"line":3774},[270,8884,8885],{},"    // IEEE 754 big-endian conversion\n",[270,8887,8888],{"class":272,"line":3780},[270,8889,8890],{},"    quint32 raw = (static_cast\u003Cquint32>(reg1) \u003C\u003C 16) | reg2;\n",[270,8892,8893],{"class":272,"line":3786},[270,8894,8895],{},"    float value;\n",[270,8897,8898],{"class":272,"line":3792},[270,8899,8900],{},"    memcpy(&value, &raw, sizeof(float));\n",[270,8902,8903],{"class":272,"line":7470},[270,8904,8905],{},"    return value;\n",[270,8907,8908],{"class":272,"line":7476},[270,8909,2129],{},[270,8911,8912],{"class":272,"line":7482},[270,8913,775],{"emptyLinePlaceholder":524},[270,8915,8916],{"class":272,"line":7488},[270,8917,8918],{},"void ModbusReader::zero()\n",[270,8920,8921],{"class":272,"line":7494},[270,8922,3812],{},[270,8924,8925],{"class":272,"line":7500},[270,8926,8927],{},"    // Write 1 to register 40201\n",[270,8929,8930],{"class":272,"line":7506},[270,8931,8932],{},"    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 200, 1);\n",[270,8934,8935],{"class":272,"line":7512},[270,8936,8937],{},"    writeUnit.setValue(0, 1);\n",[270,8939,8940],{"class":272,"line":7518},[270,8941,775],{"emptyLinePlaceholder":524},[270,8943,8944],{"class":272,"line":7524},[270,8945,8946],{},"    m_modbusClient->sendWriteRequest(writeUnit, 1);\n",[270,8948,8949],{"class":272,"line":7529},[270,8950,8951],{},"    qDebug() \u003C\u003C \"Zero command sent\";\n",[270,8953,8954],{"class":272,"line":7535},[270,8955,2129],{},[270,8957,8958],{"class":272,"line":7541},[270,8959,775],{"emptyLinePlaceholder":524},[270,8961,8962],{"class":272,"line":7547},[270,8963,8964],{},"void ModbusReader::setTare()\n",[270,8966,8967],{"class":272,"line":7552},[270,8968,3812],{},[270,8970,8971],{"class":272,"line":7558},[270,8972,8973],{},"    // Write 1 to register 40202\n",[270,8975,8976],{"class":272,"line":7564},[270,8977,8978],{},"    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 201, 1);\n",[270,8980,8981],{"class":272,"line":7570},[270,8982,8937],{},[270,8984,8985],{"class":272,"line":7576},[270,8986,775],{"emptyLinePlaceholder":524},[270,8988,8989],{"class":272,"line":7582},[270,8990,8946],{},[270,8992,8993],{"class":272,"line":7587},[270,8994,8995],{},"    qDebug() \u003C\u003C \"Tare command sent\";\n",[270,8997,8998],{"class":272,"line":7593},[270,8999,2129],{},[24,9001,9003],{"id":9002},"qml-user-interface","QML User Interface",[16,9005,9006],{},[93,9007,9008],{},[36,9009,5617],{},[29,9011,9013],{"className":5620,"code":9012,"language":5622,"meta":38,"style":38},"import QtQuick 2.15\nimport QtQuick.Controls 2.15\nimport QtQuick.Layouts 1.15\nimport QtCharts 2.15\nimport com.amazeng 1.0  // ModbusReader\n\nApplicationWindow {\n    visible: true\n    width: 1024\n    height: 600\n    title: \"GDT Weighing System\"\n\n    ModbusReader {\n        id: modbusReader\n        Component.onCompleted: {\n            connectToDevice(\"192.168.1.100\", 502)\n        }\n    }\n\n    Rectangle {\n        anchors.fill: parent\n        color: \"#1E1E1E\"\n\n        ColumnLayout {\n            anchors.fill: parent\n            anchors.margins: 20\n            spacing: 20\n\n            // Header\n            Rectangle {\n                Layout.fillWidth: true\n                height: 60\n                color: \"#2D2D2D\"\n                radius: 8\n\n                RowLayout {\n                    anchors.fill: parent\n                    anchors.margins: 10\n\n                    Text {\n                        text: \"GDT-410M Weighing Station\"\n                        font.pixelSize: 28\n                        font.bold: true\n                        color: \"#FFFFFF\"\n                    }\n\n                    Item { Layout.fillWidth: true }\n\n                    Rectangle {\n                        width: 20\n                        height: 20\n                        radius: 10\n                        color: modbusReader.connected ? \"#2ECC71\" : \"#E74C3C\"\n                    }\n\n                    Text {\n                        text: modbusReader.connected ? \"Connected\" : \"Disconnected\"\n                        font.pixelSize: 16\n                        color: \"#FFFFFF\"\n                    }\n                }\n            }\n\n            // Main weight display\n            Rectangle {\n                Layout.fillWidth: true\n                Layout.preferredHeight: 250\n                color: \"#27AE60\"\n                radius: 12\n\n                ColumnLayout {\n                    anchors.centerIn: parent\n                    spacing: 10\n\n                    Text {\n                        text: \"NET WEIGHT\"\n                        font.pixelSize: 24\n                        color: \"white\"\n                        Layout.alignment: Qt.AlignHCenter\n                    }\n\n                    Text {\n                        text: modbusReader.netWeight.toFixed(2)\n                        font.pixelSize: 96\n                        font.bold: true\n                        color: \"white\"\n                        Layout.alignment: Qt.AlignHCenter\n                    }\n\n                    Text {\n                        text: \"kg\"\n                        font.pixelSize: 36\n                        color: \"white\"\n                        Layout.alignment: Qt.AlignHCenter\n                    }\n                }\n            }\n\n            // Gross and Tare\n            RowLayout {\n                Layout.fillWidth: true\n                spacing: 20\n\n                Rectangle {\n                    Layout.fillWidth: true\n                    height: 120\n                    color: \"#34495E\"\n                    radius: 8\n\n                    ColumnLayout {\n                        anchors.centerIn: parent\n                        spacing: 5\n\n                        Text {\n                            text: \"Gross\"\n                            font.pixelSize: 18\n                            color: \"#BDC3C7\"\n                            Layout.alignment: Qt.AlignHCenter\n                        }\n\n                        Text {\n                            text: modbusReader.grossWeight.toFixed(2) + \" kg\"\n                            font.pixelSize: 32\n                            color: \"white\"\n                            Layout.alignment: Qt.AlignHCenter\n                        }\n                    }\n                }\n\n                Rectangle {\n                    Layout.fillWidth: true\n                    height: 120\n                    color: \"#34495E\"\n                    radius: 8\n\n                    ColumnLayout {\n                        anchors.centerIn: parent\n                        spacing: 5\n\n                        Text {\n                            text: \"Tare\"\n                            font.pixelSize: 18\n                            color: \"#BDC3C7\"\n                            Layout.alignment: Qt.AlignHCenter\n                        }\n\n                        Text {\n                            text: modbusReader.tare.toFixed(2) + \" kg\"\n                            font.pixelSize: 32\n                            color: \"white\"\n                            Layout.alignment: Qt.AlignHCenter\n                        }\n                    }\n                }\n            }\n\n            // Control buttons\n            RowLayout {\n                Layout.fillWidth: true\n                spacing: 20\n\n                Button {\n                    text: \"ZERO\"\n                    Layout.fillWidth: true\n                    Layout.preferredHeight: 80\n                    font.pixelSize: 24\n                    onClicked: modbusReader.zero()\n\n                    background: Rectangle {\n                        color: parent.pressed ? \"#E67E22\" : \"#F39C12\"\n                        radius: 8\n                    }\n\n                    contentItem: Text {\n                        text: parent.text\n                        font: parent.font\n                        color: \"white\"\n                        horizontalAlignment: Text.AlignHCenter\n                        verticalAlignment: Text.AlignVCenter\n                    }\n                }\n\n                Button {\n                    text: \"TARE\"\n                    Layout.fillWidth: true\n                    Layout.preferredHeight: 80\n                    font.pixelSize: 24\n                    onClicked: modbusReader.setTare()\n\n                    background: Rectangle {\n                        color: parent.pressed ? \"#2980B9\" : \"#3498DB\"\n                        radius: 8\n                    }\n\n                    contentItem: Text {\n                        text: parent.text\n                        font: parent.font\n                        color: \"white\"\n                        horizontalAlignment: Text.AlignHCenter\n                        verticalAlignment: Text.AlignVCenter\n                    }\n                }\n            }\n        }\n    }\n}\n",[36,9014,9015,9019,9023,9027,9032,9037,9041,9045,9049,9053,9057,9062,9066,9071,9076,9081,9086,9090,9094,9098,9102,9106,9111,9115,9120,9125,9130,9134,9138,9143,9147,9152,9157,9162,9167,9171,9176,9181,9186,9190,9195,9200,9205,9210,9215,9220,9224,9229,9233,9238,9243,9248,9253,9258,9262,9266,9270,9275,9280,9284,9288,9292,9296,9300,9305,9309,9313,9318,9323,9328,9332,9337,9342,9347,9351,9355,9360,9365,9370,9375,9379,9383,9387,9392,9397,9401,9405,9409,9413,9417,9421,9426,9431,9435,9439,9443,9447,9451,9455,9460,9465,9469,9474,9478,9482,9487,9492,9497,9502,9506,9511,9516,9521,9525,9530,9535,9540,9545,9550,9555,9559,9563,9569,9575,9581,9586,9591,9596,9601,9606,9611,9616,9621,9626,9631,9636,9641,9646,9651,9656,9661,9667,9672,9677,9682,9687,9692,9697,9703,9708,9713,9718,9723,9728,9733,9738,9743,9749,9754,9759,9764,9769,9775,9781,9786,9792,9798,9804,9809,9815,9821,9827,9832,9837,9843,9849,9855,9860,9866,9872,9877,9882,9887,9892,9898,9903,9908,9913,9919,9924,9929,9935,9940,9945,9950,9955,9960,9965,9970,9975,9980,9985,9990,9995,10000,10005],{"__ignoreMap":38},[270,9016,9017],{"class":272,"line":273},[270,9018,5629],{},[270,9020,9021],{"class":272,"line":279},[270,9022,5634],{},[270,9024,9025],{"class":272,"line":285},[270,9026,5639],{},[270,9028,9029],{"class":272,"line":291},[270,9030,9031],{},"import QtCharts 2.15\n",[270,9033,9034],{"class":272,"line":297},[270,9035,9036],{},"import com.amazeng 1.0  // ModbusReader\n",[270,9038,9039],{"class":272,"line":303},[270,9040,775],{"emptyLinePlaceholder":524},[270,9042,9043],{"class":272,"line":515},[270,9044,5648],{},[270,9046,9047],{"class":272,"line":793},[270,9048,5653],{},[270,9050,9051],{"class":272,"line":799},[270,9052,5658],{},[270,9054,9055],{"class":272,"line":805},[270,9056,5663],{},[270,9058,9059],{"class":272,"line":2120},[270,9060,9061],{},"    title: \"GDT Weighing System\"\n",[270,9063,9064],{"class":272,"line":2126},[270,9065,775],{"emptyLinePlaceholder":524},[270,9067,9068],{"class":272,"line":2132},[270,9069,9070],{},"    ModbusReader {\n",[270,9072,9073],{"class":272,"line":3375},[270,9074,9075],{},"        id: modbusReader\n",[270,9077,9078],{"class":272,"line":3381},[270,9079,9080],{},"        Component.onCompleted: {\n",[270,9082,9083],{"class":272,"line":3387},[270,9084,9085],{},"            connectToDevice(\"192.168.1.100\", 502)\n",[270,9087,9088],{"class":272,"line":3393},[270,9089,4491],{},[270,9091,9092],{"class":272,"line":3399},[270,9093,3795],{},[270,9095,9096],{"class":272,"line":3405},[270,9097,775],{"emptyLinePlaceholder":524},[270,9099,9100],{"class":272,"line":3411},[270,9101,5682],{},[270,9103,9104],{"class":272,"line":3417},[270,9105,5687],{},[270,9107,9108],{"class":272,"line":3423},[270,9109,9110],{},"        color: \"#1E1E1E\"\n",[270,9112,9113],{"class":272,"line":3429},[270,9114,775],{"emptyLinePlaceholder":524},[270,9116,9117],{"class":272,"line":3434},[270,9118,9119],{},"        ColumnLayout {\n",[270,9121,9122],{"class":272,"line":3440},[270,9123,9124],{},"            anchors.fill: parent\n",[270,9126,9127],{"class":272,"line":3446},[270,9128,9129],{},"            anchors.margins: 20\n",[270,9131,9132],{"class":272,"line":3452},[270,9133,5871],{},[270,9135,9136],{"class":272,"line":3457},[270,9137,775],{"emptyLinePlaceholder":524},[270,9139,9140],{"class":272,"line":3463},[270,9141,9142],{},"            // Header\n",[270,9144,9145],{"class":272,"line":3469},[270,9146,6827],{},[270,9148,9149],{"class":272,"line":3475},[270,9150,9151],{},"                Layout.fillWidth: true\n",[270,9153,9154],{"class":272,"line":3480},[270,9155,9156],{},"                height: 60\n",[270,9158,9159],{"class":272,"line":3486},[270,9160,9161],{},"                color: \"#2D2D2D\"\n",[270,9163,9164],{"class":272,"line":3492},[270,9165,9166],{},"                radius: 8\n",[270,9168,9169],{"class":272,"line":3497},[270,9170,775],{"emptyLinePlaceholder":524},[270,9172,9173],{"class":272,"line":3503},[270,9174,9175],{},"                RowLayout {\n",[270,9177,9178],{"class":272,"line":3509},[270,9179,9180],{},"                    anchors.fill: parent\n",[270,9182,9183],{"class":272,"line":3515},[270,9184,9185],{},"                    anchors.margins: 10\n",[270,9187,9188],{"class":272,"line":3521},[270,9189,775],{"emptyLinePlaceholder":524},[270,9191,9192],{"class":272,"line":3527},[270,9193,9194],{},"                    Text {\n",[270,9196,9197],{"class":272,"line":3532},[270,9198,9199],{},"                        text: \"GDT-410M Weighing Station\"\n",[270,9201,9202],{"class":272,"line":3538},[270,9203,9204],{},"                        font.pixelSize: 28\n",[270,9206,9207],{"class":272,"line":3544},[270,9208,9209],{},"                        font.bold: true\n",[270,9211,9212],{"class":272,"line":3550},[270,9213,9214],{},"                        color: \"#FFFFFF\"\n",[270,9216,9217],{"class":272,"line":3556},[270,9218,9219],{},"                    }\n",[270,9221,9222],{"class":272,"line":3562},[270,9223,775],{"emptyLinePlaceholder":524},[270,9225,9226],{"class":272,"line":3568},[270,9227,9228],{},"                    Item { Layout.fillWidth: true }\n",[270,9230,9231],{"class":272,"line":3574},[270,9232,775],{"emptyLinePlaceholder":524},[270,9234,9235],{"class":272,"line":3580},[270,9236,9237],{},"                    Rectangle {\n",[270,9239,9240],{"class":272,"line":3586},[270,9241,9242],{},"                        width: 20\n",[270,9244,9245],{"class":272,"line":3592},[270,9246,9247],{},"                        height: 20\n",[270,9249,9250],{"class":272,"line":3597},[270,9251,9252],{},"                        radius: 10\n",[270,9254,9255],{"class":272,"line":3603},[270,9256,9257],{},"                        color: modbusReader.connected ? \"#2ECC71\" : \"#E74C3C\"\n",[270,9259,9260],{"class":272,"line":3609},[270,9261,9219],{},[270,9263,9264],{"class":272,"line":3615},[270,9265,775],{"emptyLinePlaceholder":524},[270,9267,9268],{"class":272,"line":3621},[270,9269,9194],{},[270,9271,9272],{"class":272,"line":3627},[270,9273,9274],{},"                        text: modbusReader.connected ? \"Connected\" : \"Disconnected\"\n",[270,9276,9277],{"class":272,"line":3633},[270,9278,9279],{},"                        font.pixelSize: 16\n",[270,9281,9282],{"class":272,"line":3639},[270,9283,9214],{},[270,9285,9286],{"class":272,"line":3645},[270,9287,9219],{},[270,9289,9290],{"class":272,"line":3651},[270,9291,3672],{},[270,9293,9294],{"class":272,"line":3657},[270,9295,4592],{},[270,9297,9298],{"class":272,"line":3663},[270,9299,775],{"emptyLinePlaceholder":524},[270,9301,9302],{"class":272,"line":3669},[270,9303,9304],{},"            // Main weight display\n",[270,9306,9307],{"class":272,"line":3675},[270,9308,6827],{},[270,9310,9311],{"class":272,"line":3681},[270,9312,9151],{},[270,9314,9315],{"class":272,"line":3687},[270,9316,9317],{},"                Layout.preferredHeight: 250\n",[270,9319,9320],{"class":272,"line":3693},[270,9321,9322],{},"                color: \"#27AE60\"\n",[270,9324,9325],{"class":272,"line":3698},[270,9326,9327],{},"                radius: 12\n",[270,9329,9330],{"class":272,"line":3704},[270,9331,775],{"emptyLinePlaceholder":524},[270,9333,9334],{"class":272,"line":3710},[270,9335,9336],{},"                ColumnLayout {\n",[270,9338,9339],{"class":272,"line":3716},[270,9340,9341],{},"                    anchors.centerIn: parent\n",[270,9343,9344],{"class":272,"line":3721},[270,9345,9346],{},"                    spacing: 10\n",[270,9348,9349],{"class":272,"line":3727},[270,9350,775],{"emptyLinePlaceholder":524},[270,9352,9353],{"class":272,"line":3733},[270,9354,9194],{},[270,9356,9357],{"class":272,"line":3739},[270,9358,9359],{},"                        text: \"NET WEIGHT\"\n",[270,9361,9362],{"class":272,"line":3745},[270,9363,9364],{},"                        font.pixelSize: 24\n",[270,9366,9367],{"class":272,"line":3751},[270,9368,9369],{},"                        color: \"white\"\n",[270,9371,9372],{"class":272,"line":3757},[270,9373,9374],{},"                        Layout.alignment: Qt.AlignHCenter\n",[270,9376,9377],{"class":272,"line":3763},[270,9378,9219],{},[270,9380,9381],{"class":272,"line":3769},[270,9382,775],{"emptyLinePlaceholder":524},[270,9384,9385],{"class":272,"line":3774},[270,9386,9194],{},[270,9388,9389],{"class":272,"line":3780},[270,9390,9391],{},"                        text: modbusReader.netWeight.toFixed(2)\n",[270,9393,9394],{"class":272,"line":3786},[270,9395,9396],{},"                        font.pixelSize: 96\n",[270,9398,9399],{"class":272,"line":3792},[270,9400,9209],{},[270,9402,9403],{"class":272,"line":7470},[270,9404,9369],{},[270,9406,9407],{"class":272,"line":7476},[270,9408,9374],{},[270,9410,9411],{"class":272,"line":7482},[270,9412,9219],{},[270,9414,9415],{"class":272,"line":7488},[270,9416,775],{"emptyLinePlaceholder":524},[270,9418,9419],{"class":272,"line":7494},[270,9420,9194],{},[270,9422,9423],{"class":272,"line":7500},[270,9424,9425],{},"                        text: \"kg\"\n",[270,9427,9428],{"class":272,"line":7506},[270,9429,9430],{},"                        font.pixelSize: 36\n",[270,9432,9433],{"class":272,"line":7512},[270,9434,9369],{},[270,9436,9437],{"class":272,"line":7518},[270,9438,9374],{},[270,9440,9441],{"class":272,"line":7524},[270,9442,9219],{},[270,9444,9445],{"class":272,"line":7529},[270,9446,3672],{},[270,9448,9449],{"class":272,"line":7535},[270,9450,4592],{},[270,9452,9453],{"class":272,"line":7541},[270,9454,775],{"emptyLinePlaceholder":524},[270,9456,9457],{"class":272,"line":7547},[270,9458,9459],{},"            // Gross and Tare\n",[270,9461,9462],{"class":272,"line":7552},[270,9463,9464],{},"            RowLayout {\n",[270,9466,9467],{"class":272,"line":7558},[270,9468,9151],{},[270,9470,9471],{"class":272,"line":7564},[270,9472,9473],{},"                spacing: 20\n",[270,9475,9476],{"class":272,"line":7570},[270,9477,775],{"emptyLinePlaceholder":524},[270,9479,9480],{"class":272,"line":7576},[270,9481,6977],{},[270,9483,9484],{"class":272,"line":7582},[270,9485,9486],{},"                    Layout.fillWidth: true\n",[270,9488,9489],{"class":272,"line":7587},[270,9490,9491],{},"                    height: 120\n",[270,9493,9494],{"class":272,"line":7593},[270,9495,9496],{},"                    color: \"#34495E\"\n",[270,9498,9499],{"class":272,"line":7599},[270,9500,9501],{},"                    radius: 8\n",[270,9503,9504],{"class":272,"line":7605},[270,9505,775],{"emptyLinePlaceholder":524},[270,9507,9508],{"class":272,"line":7610},[270,9509,9510],{},"                    ColumnLayout {\n",[270,9512,9513],{"class":272,"line":7616},[270,9514,9515],{},"                        anchors.centerIn: parent\n",[270,9517,9518],{"class":272,"line":7622},[270,9519,9520],{},"                        spacing: 5\n",[270,9522,9523],{"class":272,"line":7627},[270,9524,775],{"emptyLinePlaceholder":524},[270,9526,9527],{"class":272,"line":7633},[270,9528,9529],{},"                        Text {\n",[270,9531,9532],{"class":272,"line":7638},[270,9533,9534],{},"                            text: \"Gross\"\n",[270,9536,9537],{"class":272,"line":7644},[270,9538,9539],{},"                            font.pixelSize: 18\n",[270,9541,9542],{"class":272,"line":7650},[270,9543,9544],{},"                            color: \"#BDC3C7\"\n",[270,9546,9547],{"class":272,"line":7656},[270,9548,9549],{},"                            Layout.alignment: Qt.AlignHCenter\n",[270,9551,9552],{"class":272,"line":7661},[270,9553,9554],{},"                        }\n",[270,9556,9557],{"class":272,"line":7667},[270,9558,775],{"emptyLinePlaceholder":524},[270,9560,9561],{"class":272,"line":7673},[270,9562,9529],{},[270,9564,9566],{"class":272,"line":9565},122,[270,9567,9568],{},"                            text: modbusReader.grossWeight.toFixed(2) + \" kg\"\n",[270,9570,9572],{"class":272,"line":9571},123,[270,9573,9574],{},"                            font.pixelSize: 32\n",[270,9576,9578],{"class":272,"line":9577},124,[270,9579,9580],{},"                            color: \"white\"\n",[270,9582,9584],{"class":272,"line":9583},125,[270,9585,9549],{},[270,9587,9589],{"class":272,"line":9588},126,[270,9590,9554],{},[270,9592,9594],{"class":272,"line":9593},127,[270,9595,9219],{},[270,9597,9599],{"class":272,"line":9598},128,[270,9600,3672],{},[270,9602,9604],{"class":272,"line":9603},129,[270,9605,775],{"emptyLinePlaceholder":524},[270,9607,9609],{"class":272,"line":9608},130,[270,9610,6977],{},[270,9612,9614],{"class":272,"line":9613},131,[270,9615,9486],{},[270,9617,9619],{"class":272,"line":9618},132,[270,9620,9491],{},[270,9622,9624],{"class":272,"line":9623},133,[270,9625,9496],{},[270,9627,9629],{"class":272,"line":9628},134,[270,9630,9501],{},[270,9632,9634],{"class":272,"line":9633},135,[270,9635,775],{"emptyLinePlaceholder":524},[270,9637,9639],{"class":272,"line":9638},136,[270,9640,9510],{},[270,9642,9644],{"class":272,"line":9643},137,[270,9645,9515],{},[270,9647,9649],{"class":272,"line":9648},138,[270,9650,9520],{},[270,9652,9654],{"class":272,"line":9653},139,[270,9655,775],{"emptyLinePlaceholder":524},[270,9657,9659],{"class":272,"line":9658},140,[270,9660,9529],{},[270,9662,9664],{"class":272,"line":9663},141,[270,9665,9666],{},"                            text: \"Tare\"\n",[270,9668,9670],{"class":272,"line":9669},142,[270,9671,9539],{},[270,9673,9675],{"class":272,"line":9674},143,[270,9676,9544],{},[270,9678,9680],{"class":272,"line":9679},144,[270,9681,9549],{},[270,9683,9685],{"class":272,"line":9684},145,[270,9686,9554],{},[270,9688,9690],{"class":272,"line":9689},146,[270,9691,775],{"emptyLinePlaceholder":524},[270,9693,9695],{"class":272,"line":9694},147,[270,9696,9529],{},[270,9698,9700],{"class":272,"line":9699},148,[270,9701,9702],{},"                            text: modbusReader.tare.toFixed(2) + \" kg\"\n",[270,9704,9706],{"class":272,"line":9705},149,[270,9707,9574],{},[270,9709,9711],{"class":272,"line":9710},150,[270,9712,9580],{},[270,9714,9716],{"class":272,"line":9715},151,[270,9717,9549],{},[270,9719,9721],{"class":272,"line":9720},152,[270,9722,9554],{},[270,9724,9726],{"class":272,"line":9725},153,[270,9727,9219],{},[270,9729,9731],{"class":272,"line":9730},154,[270,9732,3672],{},[270,9734,9736],{"class":272,"line":9735},155,[270,9737,4592],{},[270,9739,9741],{"class":272,"line":9740},156,[270,9742,775],{"emptyLinePlaceholder":524},[270,9744,9746],{"class":272,"line":9745},157,[270,9747,9748],{},"            // Control buttons\n",[270,9750,9752],{"class":272,"line":9751},158,[270,9753,9464],{},[270,9755,9757],{"class":272,"line":9756},159,[270,9758,9151],{},[270,9760,9762],{"class":272,"line":9761},160,[270,9763,9473],{},[270,9765,9767],{"class":272,"line":9766},161,[270,9768,775],{"emptyLinePlaceholder":524},[270,9770,9772],{"class":272,"line":9771},162,[270,9773,9774],{},"                Button {\n",[270,9776,9778],{"class":272,"line":9777},163,[270,9779,9780],{},"                    text: \"ZERO\"\n",[270,9782,9784],{"class":272,"line":9783},164,[270,9785,9486],{},[270,9787,9789],{"class":272,"line":9788},165,[270,9790,9791],{},"                    Layout.preferredHeight: 80\n",[270,9793,9795],{"class":272,"line":9794},166,[270,9796,9797],{},"                    font.pixelSize: 24\n",[270,9799,9801],{"class":272,"line":9800},167,[270,9802,9803],{},"                    onClicked: modbusReader.zero()\n",[270,9805,9807],{"class":272,"line":9806},168,[270,9808,775],{"emptyLinePlaceholder":524},[270,9810,9812],{"class":272,"line":9811},169,[270,9813,9814],{},"                    background: Rectangle {\n",[270,9816,9818],{"class":272,"line":9817},170,[270,9819,9820],{},"                        color: parent.pressed ? \"#E67E22\" : \"#F39C12\"\n",[270,9822,9824],{"class":272,"line":9823},171,[270,9825,9826],{},"                        radius: 8\n",[270,9828,9830],{"class":272,"line":9829},172,[270,9831,9219],{},[270,9833,9835],{"class":272,"line":9834},173,[270,9836,775],{"emptyLinePlaceholder":524},[270,9838,9840],{"class":272,"line":9839},174,[270,9841,9842],{},"                    contentItem: Text {\n",[270,9844,9846],{"class":272,"line":9845},175,[270,9847,9848],{},"                        text: parent.text\n",[270,9850,9852],{"class":272,"line":9851},176,[270,9853,9854],{},"                        font: parent.font\n",[270,9856,9858],{"class":272,"line":9857},177,[270,9859,9369],{},[270,9861,9863],{"class":272,"line":9862},178,[270,9864,9865],{},"                        horizontalAlignment: Text.AlignHCenter\n",[270,9867,9869],{"class":272,"line":9868},179,[270,9870,9871],{},"                        verticalAlignment: Text.AlignVCenter\n",[270,9873,9875],{"class":272,"line":9874},180,[270,9876,9219],{},[270,9878,9880],{"class":272,"line":9879},181,[270,9881,3672],{},[270,9883,9885],{"class":272,"line":9884},182,[270,9886,775],{"emptyLinePlaceholder":524},[270,9888,9890],{"class":272,"line":9889},183,[270,9891,9774],{},[270,9893,9895],{"class":272,"line":9894},184,[270,9896,9897],{},"                    text: \"TARE\"\n",[270,9899,9901],{"class":272,"line":9900},185,[270,9902,9486],{},[270,9904,9906],{"class":272,"line":9905},186,[270,9907,9791],{},[270,9909,9911],{"class":272,"line":9910},187,[270,9912,9797],{},[270,9914,9916],{"class":272,"line":9915},188,[270,9917,9918],{},"                    onClicked: modbusReader.setTare()\n",[270,9920,9922],{"class":272,"line":9921},189,[270,9923,775],{"emptyLinePlaceholder":524},[270,9925,9927],{"class":272,"line":9926},190,[270,9928,9814],{},[270,9930,9932],{"class":272,"line":9931},191,[270,9933,9934],{},"                        color: parent.pressed ? \"#2980B9\" : \"#3498DB\"\n",[270,9936,9938],{"class":272,"line":9937},192,[270,9939,9826],{},[270,9941,9943],{"class":272,"line":9942},193,[270,9944,9219],{},[270,9946,9948],{"class":272,"line":9947},194,[270,9949,775],{"emptyLinePlaceholder":524},[270,9951,9953],{"class":272,"line":9952},195,[270,9954,9842],{},[270,9956,9958],{"class":272,"line":9957},196,[270,9959,9848],{},[270,9961,9963],{"class":272,"line":9962},197,[270,9964,9854],{},[270,9966,9968],{"class":272,"line":9967},198,[270,9969,9369],{},[270,9971,9973],{"class":272,"line":9972},199,[270,9974,9865],{},[270,9976,9978],{"class":272,"line":9977},200,[270,9979,9871],{},[270,9981,9983],{"class":272,"line":9982},201,[270,9984,9219],{},[270,9986,9988],{"class":272,"line":9987},202,[270,9989,3672],{},[270,9991,9993],{"class":272,"line":9992},203,[270,9994,4592],{},[270,9996,9998],{"class":272,"line":9997},204,[270,9999,4491],{},[270,10001,10003],{"class":272,"line":10002},205,[270,10004,3795],{},[270,10006,10008],{"class":272,"line":10007},206,[270,10009,2129],{},[11,10011,10013],{"id":10012},"real-world-application-automatic-packaging-line","Real-World Application: Automatic Packaging Line",[24,10015,3294],{"id":3293},[16,10017,10018],{},"Products are weighed and automatically recorded in a packaging line.",[16,10020,10021],{},[93,10022,10023],{},"Requirements:",[176,10025,10026,10032,10038],{},[43,10027,10028,10031],{},[93,10029,10030],{},"Target Weight:"," 25 kg ± 0.1 kg",[43,10033,10034,10037],{},[93,10035,10036],{},"Automatic Recording:"," Product over threshold → Save to database",[43,10039,10040,10043],{},[93,10041,10042],{},"Tare:"," Automatic tare after every 10 weighing operations",[24,10045,10047],{"id":10046},"implementation","Implementation",[16,10049,10050],{},[93,10051,10052],{},"Data Recording (SQLite):",[29,10054,10056],{"className":264,"code":10055,"language":266,"meta":38,"style":38},"// DatabaseManager.cpp\nvoid DatabaseManager::saveWeighing(float weight, const QString &batchCode)\n{\n    QSqlQuery query(m_db);\n    query.prepare(\"INSERT INTO weighings (timestamp, weight, batch_code) \"\n                  \"VALUES (datetime('now'), :weight, :batch)\");\n    query.bindValue(\":weight\", weight);\n    query.bindValue(\":batch\", batchCode);\n    query.exec();\n}\n",[36,10057,10058,10063,10068,10072,10077,10082,10087,10092,10097,10102],{"__ignoreMap":38},[270,10059,10060],{"class":272,"line":273},[270,10061,10062],{},"// DatabaseManager.cpp\n",[270,10064,10065],{"class":272,"line":279},[270,10066,10067],{},"void DatabaseManager::saveWeighing(float weight, const QString &batchCode)\n",[270,10069,10070],{"class":272,"line":285},[270,10071,3812],{},[270,10073,10074],{"class":272,"line":291},[270,10075,10076],{},"    QSqlQuery query(m_db);\n",[270,10078,10079],{"class":272,"line":297},[270,10080,10081],{},"    query.prepare(\"INSERT INTO weighings (timestamp, weight, batch_code) \"\n",[270,10083,10084],{"class":272,"line":303},[270,10085,10086],{},"                  \"VALUES (datetime('now'), :weight, :batch)\");\n",[270,10088,10089],{"class":272,"line":515},[270,10090,10091],{},"    query.bindValue(\":weight\", weight);\n",[270,10093,10094],{"class":272,"line":793},[270,10095,10096],{},"    query.bindValue(\":batch\", batchCode);\n",[270,10098,10099],{"class":272,"line":799},[270,10100,10101],{},"    query.exec();\n",[270,10103,10104],{"class":272,"line":805},[270,10105,2129],{},[11,10107,10109],{"id":10108},"gdt-hmi-aws-integration","GDT + HMI + AWS Integration",[16,10111,1718,10112,10114,10115,10117,10118,10120],{},[463,10113,2840],{"href":1723}," + ",[463,10116,518],{"href":2464}," combination can also send data to the cloud. Details in our ",[463,10119,2983],{"href":2634}," solution:",[29,10122,10125],{"className":10123,"code":10124,"language":34},[32],"GDT (Modbus) → HMI (Gateway) → MQTT → AWS IoT Core\n",[36,10126,10124],{"__ignoreMap":38},[16,10128,10129],{},"HMI panel:",[40,10131,10132,10135,10138],{},[43,10133,10134],{},"Displays weight locally (Qt/QML interface)",[43,10136,10137],{},"Publishes to AWS IoT Core (MQTT client)",[43,10139,10140],{},"Stores in database (SQLite/PostgreSQL)",[11,10142,444],{"id":443},[16,10144,1718,10145,467,10147,10149],{},[463,10146,471],{"href":1723},[463,10148,2465],{"href":2464}," integration provides:",[16,10151,10152,10153,10156,10158,10159,10161,10163,10164,10167,5098,10169,10172],{},"✅ Real-time weight monitoring with ",[93,10154,10155],{},"200ms update rate",[2353,10157],{},"\n✅ Modern touchscreen interface with ",[93,10160,5230],{},[2353,10162],{},"\n✅ Flexible communication with ",[93,10165,10166],{},"Modbus TCP/RTU",[2353,10168],{},[93,10170,10171],{},"Cloud integration"," ready (AWS, Azure)",[24,10174,5132],{"id":5131},[40,10176,10177,10181,10185,10190],{},[43,10178,10179],{},[463,10180,471],{"href":1723},[43,10182,10183],{},[463,10184,2465],{"href":2464},[43,10186,10187],{},[463,10188,10189],{"href":6156},"Embedded Linux HMI Development: Yocto + Qt",[43,10191,10192],{},[463,10193,2983],{"href":2634},[477,10195,479],{},{"title":38,"searchDepth":279,"depth":279,"links":10197},[10198,10199,10200,10201,10205,10209,10210],{"id":13,"depth":279,"text":14},{"id":3279,"depth":279,"text":3280},{"id":8035,"depth":279,"text":8036},{"id":8236,"depth":279,"text":8237,"children":10202},[10203,10204],{"id":8240,"depth":285,"text":8241},{"id":9002,"depth":285,"text":9003},{"id":10012,"depth":279,"text":10013,"children":10206},[10207,10208],{"id":3293,"depth":285,"text":3294},{"id":10046,"depth":285,"text":10047},{"id":10108,"depth":279,"text":10109},{"id":443,"depth":279,"text":444,"children":10211},[10212],{"id":5131,"depth":285,"text":5132},"Step-by-step guide for visualizing data from GDT Digital Transmitter on HMI touchscreen with Modbus TCP/RTU protocol in industrial weighing systems.",{"date":3011,"author":514,"readTime":799,"tags":10215},[2840,518,10216,10217,521,10218,255],"Modbus","Loadcell","Industrial Weighing","/en/blog/gdt-hmi-integration-modbus-weight-display",{"title":7994,"description":10213},"en/blog/gdt-hmi-integration-modbus-weight-display","_zBAhz4pJw9k2b4kX1YxzG1n39nHwxqPQ22nMjN0eis",{"id":10224,"title":10225,"body":10226,"description":11403,"extension":511,"meta":11404,"navigation":524,"path":2340,"seo":11408,"stem":11409,"__hash__":11410},"en_blog/en/blog/industrial-data-collection-with-aws-iot-core.md","Industrial Data Collection with AWS IoT Core: From ZMA Devices to Cloud",{"type":8,"value":10227,"toc":11380},[10228,10230,10249,10262,10266,10272,10276,10299,10303,10331,10340,10344,10348,10351,10421,10425,10431,10490,10500,10504,10508,10513,11091,11095,11099,11106,11214,11218,11222,11318,11321,11323,11336,11348,11357,11359,11377],[11,10229,14],{"id":13},[16,10231,10232,10233,467,10236,10239,10240,8017,10242,10244,10245,10248],{},"Moving industrial data to the cloud is the cornerstone of ",[93,10234,10235],{},"Industry 4.0",[93,10237,10238],{},"predictive maintenance"," processes. However, data collected from sensors in the field typically communicate using traditional protocols like ",[93,10241,8020],{},[93,10243,687],{},". An ",[93,10246,10247],{},"IoT Gateway"," is required to transfer this data to cloud platforms like AWS IoT Core.",[16,10250,10251,10252,467,10254,10256,10257,10259,10260,472],{},"In this article, we examine in detail how data collected via Modbus from our ",[463,10253,466],{"href":1613},[463,10255,471],{"href":1723}," devices is transferred to ",[93,10258,2341],{}," through an ",[93,10261,10247],{},[11,10263,10265],{"id":10264},"architecture-overview","Architecture Overview",[29,10267,10270],{"className":10268,"code":10269,"language":34},[32],"┌─────────────────────────────────────────────────────────────┐\n│                    Factory / Field                          │\n│                                                             │\n│  ┌─────────┐    Modbus RTU/TCP    ┌──────────────┐        │\n│  │ ZMA-4   │◄────────────────────►│              │        │\n│  │ Device  │                      │  IoT Gateway │        │\n│  └─────────┘                      │  (Linux Box) │        │\n│                                   │              │        │\n│  ┌─────────┐    Modbus RTU/TCP    │  - Modbus    │        │\n│  │ GDT     │◄────────────────────►│    Client    │        │\n│  │ Trans.  │                      │  - MQTT      │        │\n│  └─────────┘                      │    Client    │        │\n│                                   │  - TLS/SSL   │        │\n│                                   └───────┬──────┘        │\n└───────────────────────────────────────────┼───────────────┘\n                                            │\n                                            │ MQTT over TLS\n                                            │ Port 8883\n                                            ▼\n                                   ┌────────────────┐\n                                   │   AWS Cloud    │\n                                   │                │\n                                   │  ┌──────────┐  │\n                                   │  │ IoT Core │  │\n                                   │  └────┬─────┘  │\n                                   │       │        │\n                                   │  ┌────▼─────┐  │\n                                   │  │Timestream│  │\n                                   │  └──────────┘  │\n                                   └────────────────┘\n",[36,10271,10269],{"__ignoreMap":38},[11,10273,10275],{"id":10274},"important-note-iot-gateway-requirement","Important Note: IoT Gateway Requirement",[16,10277,10278,467,10280,10282,10283,10285,10286,10288,10289,10291,10292,10294,10295,10298],{},[93,10279,1360],{},[93,10281,2840],{}," devices communicate via ",[93,10284,8020],{}," (RS485) and ",[93,10287,687],{}," (Ethernet) protocols. AWS IoT Core uses the ",[93,10290,6010],{}," protocol. An ",[93,10293,10247],{}," device is needed to perform ",[93,10296,10297],{},"protocol conversion"," between these two worlds.",[24,10300,10302],{"id":10301},"gateway-options","Gateway Options",[176,10304,10305,10311,10317,10325],{},[43,10306,10307,10310],{},[93,10308,10309],{},"Raspberry Pi / Jetson Nano",": Linux-based, custom script with Python/Node.js",[43,10312,10313,10316],{},[93,10314,10315],{},"Industrial IoT Gateways",": Ready solutions like Moxa, Advantech, Siemens",[43,10318,10319,10324],{},[93,10320,10321],{},[463,10322,10323],{"href":2464},"Our HMI Panel",": Can function as both HMI and gateway on Embedded Linux",[43,10326,10327,10330],{},[93,10328,10329],{},"PLC + OPC UA",": Cloud connection via PLC's OPC UA server",[16,10332,10333,10334,10114,10336,10339],{},"In this article, we'll examine a custom gateway solution with ",[93,10335,317],{},[93,10337,10338],{},"Python",", but the same logic applies to all platforms.",[11,10341,10343],{"id":10342},"aws-iot-core-setup","AWS IoT Core Setup",[24,10345,10347],{"id":10346},"_1-create-thing-device","1. Create Thing (Device)",[16,10349,10350],{},"AWS Console → IoT Core → Manage → Things → Create",[29,10352,10354],{"className":3803,"code":10353,"language":3805,"meta":38,"style":38},"{\n  \"thingName\": \"amazeng-factory-gateway-01\",\n  \"thingTypeName\": \"ModbusGateway\",\n  \"attributes\": {\n    \"location\": \"Istanbul-Factory-A\",\n    \"firmware\": \"1.0.0\"\n  }\n}\n",[36,10355,10356,10360,10372,10384,10391,10403,10413,10417],{"__ignoreMap":38},[270,10357,10358],{"class":272,"line":273},[270,10359,3812],{"class":1918},[270,10361,10362,10365,10367,10370],{"class":272,"line":279},[270,10363,10364],{"class":2053},"  \"thingName\"",[270,10366,1927],{"class":1918},[270,10368,10369],{"class":1930},"\"amazeng-factory-gateway-01\"",[270,10371,3825],{"class":1918},[270,10373,10374,10377,10379,10382],{"class":272,"line":285},[270,10375,10376],{"class":2053},"  \"thingTypeName\"",[270,10378,1927],{"class":1918},[270,10380,10381],{"class":1930},"\"ModbusGateway\"",[270,10383,3825],{"class":1918},[270,10385,10386,10389],{"class":272,"line":291},[270,10387,10388],{"class":2053},"  \"attributes\"",[270,10390,6468],{"class":1918},[270,10392,10393,10396,10398,10401],{"class":272,"line":297},[270,10394,10395],{"class":2053},"    \"location\"",[270,10397,1927],{"class":1918},[270,10399,10400],{"class":1930},"\"Istanbul-Factory-A\"",[270,10402,3825],{"class":1918},[270,10404,10405,10408,10410],{"class":272,"line":303},[270,10406,10407],{"class":2053},"    \"firmware\"",[270,10409,1927],{"class":1918},[270,10411,10412],{"class":1930},"\"1.0.0\"\n",[270,10414,10415],{"class":272,"line":515},[270,10416,6564],{"class":1918},[270,10418,10419],{"class":272,"line":793},[270,10420,2129],{"class":1918},[24,10422,10424],{"id":10423},"_2-create-and-download-certificate","2. Create and Download Certificate",[16,10426,10427,10428,1015],{},"Each IoT device connects to AWS with ",[93,10429,10430],{},"X.509 certificate",[29,10432,10434],{"className":1993,"code":10433,"language":1995,"meta":38,"style":38},"# Create certificate with AWS CLI\naws iot create-keys-and-certificate \\\n  --set-as-active \\\n  --certificate-pem-outfile gateway-cert.pem \\\n  --public-key-outfile gateway-public.key \\\n  --private-key-outfile gateway-private.key\n",[36,10435,10436,10441,10455,10462,10472,10482],{"__ignoreMap":38},[270,10437,10438],{"class":272,"line":273},[270,10439,10440],{"class":2002},"# Create certificate with AWS CLI\n",[270,10442,10443,10446,10449,10452],{"class":272,"line":279},[270,10444,10445],{"class":2008},"aws",[270,10447,10448],{"class":1930}," iot",[270,10450,10451],{"class":1930}," create-keys-and-certificate",[270,10453,10454],{"class":2053}," \\\n",[270,10456,10457,10460],{"class":272,"line":285},[270,10458,10459],{"class":2053},"  --set-as-active",[270,10461,10454],{"class":2053},[270,10463,10464,10467,10470],{"class":272,"line":291},[270,10465,10466],{"class":2053},"  --certificate-pem-outfile",[270,10468,10469],{"class":1930}," gateway-cert.pem",[270,10471,10454],{"class":2053},[270,10473,10474,10477,10480],{"class":272,"line":297},[270,10475,10476],{"class":2053},"  --public-key-outfile",[270,10478,10479],{"class":1930}," gateway-public.key",[270,10481,10454],{"class":2053},[270,10483,10484,10487],{"class":272,"line":303},[270,10485,10486],{"class":2053},"  --private-key-outfile",[270,10488,10489],{"class":1930}," gateway-private.key\n",[16,10491,10492,10495,10496,10499],{},[93,10493,10494],{},"Important",": Store ",[36,10497,10498],{},"gateway-private.key"," file securely, cannot be downloaded again!",[11,10501,10503],{"id":10502},"iot-gateway-software-python","IoT Gateway Software (Python)",[24,10505,10507],{"id":10506},"gateway-application","Gateway Application",[16,10509,10510],{},[93,10511,10512],{},"gateway.py",[29,10514,10516],{"className":751,"code":10515,"language":753,"meta":38,"style":38},"#!/usr/bin/env python3\n\nimport json\nimport time\nimport struct\nfrom pymodbus.client.sync import ModbusTcpClient\nfrom awscrt import io, mqtt\nfrom awsiot import mqtt_connection_builder\n\nclass ModbusToMQTTGateway:\n    def __init__(self, config_file):\n        with open(config_file, 'r') as f:\n            self.config = json.load(f)\n\n        self.modbus_clients = {}\n        self.mqtt_connection = None\n\n        # Create Modbus clients\n        for device in self.config['modbus_devices']:\n            if device['type'] == 'tcp':\n                client = ModbusTcpClient(device['host'], port=device['port'])\n\n            client.connect()\n            self.modbus_clients[device['name']] = {\n                'client': client,\n                'config': device\n            }\n\n        # AWS IoT MQTT connection\n        self._setup_mqtt()\n\n    def _setup_mqtt(self):\n        \"\"\"Setup AWS IoT Core MQTT connection\"\"\"\n        aws_config = self.config['aws_iot']\n        cert_path = aws_config['cert_path']\n\n        # Secure connection with TLS\n        self.mqtt_connection = mqtt_connection_builder.mtls_from_path(\n            endpoint=aws_config['endpoint'],\n            port=aws_config['port'],\n            cert_filepath=f\"{cert_path}gateway-cert.pem\",\n            pri_key_filepath=f\"{cert_path}gateway-private.key\",\n            ca_filepath=f\"{cert_path}AmazonRootCA1.pem\",\n            client_id=aws_config['thing_name'],\n            clean_session=False,\n            keep_alive_secs=30\n        )\n\n        # Connect\n        connect_future = self.mqtt_connection.connect()\n        connect_future.result()\n        print(f\"✓ Connected to AWS IoT Core: {aws_config['endpoint']}\")\n\n    def read_modbus_device(self, device_name):\n        \"\"\"Read all registers from a Modbus device\"\"\"\n        device = self.modbus_clients[device_name]\n        client = device['client']\n        config = device['config']\n\n        data = {\n            'device_name': device_name,\n            'timestamp': int(time.time() * 1000),\n            'values': {}\n        }\n\n        for register in config['registers']:\n            try:\n                # Read holding register\n                result = client.read_holding_registers(\n                    address=register['address'],\n                    count=register['count'],\n                    unit=config['unit_id']\n                )\n\n                if not result.isError():\n                    # Float conversion (IEEE 754)\n                    if register['type'] == 'float' and register['count'] == 2:\n                        raw = (result.registers[0] \u003C\u003C 16) | result.registers[1]\n                        value = struct.unpack('f', struct.pack('I', raw))[0]\n\n                    data['values'][register['name']] = round(value, 3)\n\n            except Exception as e:\n                print(f\"✗ Error: {device_name} - {e}\")\n                data['values'][register['name']] = None\n\n        return data\n\n    def publish_to_aws(self, device_name, data):\n        \"\"\"Publish data to AWS IoT Core\"\"\"\n        topic = f\"{self.config['aws_iot']['topic_prefix']}/{device_name}/data\"\n        payload = json.dumps(data)\n\n        self.mqtt_connection.publish(\n            topic=topic,\n            payload=payload,\n            qos=mqtt.QoS.AT_LEAST_ONCE\n        )\n\n        print(f\"→ Published to {topic}: {payload}\")\n\n    def run(self):\n        \"\"\"Main loop: Read from Modbus, send to MQTT\"\"\"\n        interval = self.config['polling_interval']\n\n        print(f\"Gateway started. Polling interval: {interval}s\")\n\n        try:\n            while True:\n                for device_name in self.modbus_clients.keys():\n                    # Read from Modbus\n                    data = self.read_modbus_device(device_name)\n\n                    # Send to AWS\n                    self.publish_to_aws(device_name, data)\n\n                time.sleep(interval)\n\n        except KeyboardInterrupt:\n            print(\"\\nStopping gateway...\")\n            self.shutdown()\n\nif __name__ == \"__main__\":\n    gateway = ModbusToMQTTGateway('/etc/iot-gateway/config.json')\n    gateway.run()\n",[36,10517,10518,10522,10526,10530,10534,10539,10543,10548,10552,10556,10561,10566,10571,10576,10580,10584,10589,10593,10598,10603,10608,10613,10617,10621,10626,10631,10636,10640,10644,10649,10654,10658,10663,10667,10672,10677,10681,10686,10691,10696,10701,10706,10711,10716,10721,10725,10729,10733,10737,10742,10747,10752,10757,10761,10766,10771,10776,10781,10786,10790,10795,10800,10805,10810,10814,10818,10823,10828,10833,10838,10843,10848,10853,10858,10862,10867,10872,10877,10882,10887,10891,10896,10900,10905,10910,10915,10919,10924,10928,10933,10937,10942,10946,10950,10954,10958,10962,10967,10971,10975,10980,10984,10988,10993,10998,11002,11007,11011,11015,11019,11024,11029,11034,11038,11043,11048,11052,11057,11061,11065,11070,11074,11078,11082,11087],{"__ignoreMap":38},[270,10519,10520],{"class":272,"line":273},[270,10521,7066],{},[270,10523,10524],{"class":272,"line":279},[270,10525,775],{"emptyLinePlaceholder":524},[270,10527,10528],{"class":272,"line":285},[270,10529,3319],{},[270,10531,10532],{"class":272,"line":291},[270,10533,7075],{},[270,10535,10536],{"class":272,"line":297},[270,10537,10538],{},"import struct\n",[270,10540,10541],{"class":272,"line":303},[270,10542,7085],{},[270,10544,10545],{"class":272,"line":515},[270,10546,10547],{},"from awscrt import io, mqtt\n",[270,10549,10550],{"class":272,"line":793},[270,10551,7090],{},[270,10553,10554],{"class":272,"line":799},[270,10555,775],{"emptyLinePlaceholder":524},[270,10557,10558],{"class":272,"line":805},[270,10559,10560],{},"class ModbusToMQTTGateway:\n",[270,10562,10563],{"class":272,"line":2120},[270,10564,10565],{},"    def __init__(self, config_file):\n",[270,10567,10568],{"class":272,"line":2126},[270,10569,10570],{},"        with open(config_file, 'r') as f:\n",[270,10572,10573],{"class":272,"line":2132},[270,10574,10575],{},"            self.config = json.load(f)\n",[270,10577,10578],{"class":272,"line":3375},[270,10579,775],{"emptyLinePlaceholder":524},[270,10581,10582],{"class":272,"line":3381},[270,10583,7148],{},[270,10585,10586],{"class":272,"line":3387},[270,10587,10588],{},"        self.mqtt_connection = None\n",[270,10590,10591],{"class":272,"line":3393},[270,10592,775],{"emptyLinePlaceholder":524},[270,10594,10595],{"class":272,"line":3399},[270,10596,10597],{},"        # Create Modbus clients\n",[270,10599,10600],{"class":272,"line":3405},[270,10601,10602],{},"        for device in self.config['modbus_devices']:\n",[270,10604,10605],{"class":272,"line":3411},[270,10606,10607],{},"            if device['type'] == 'tcp':\n",[270,10609,10610],{"class":272,"line":3417},[270,10611,10612],{},"                client = ModbusTcpClient(device['host'], port=device['port'])\n",[270,10614,10615],{"class":272,"line":3423},[270,10616,775],{"emptyLinePlaceholder":524},[270,10618,10619],{"class":272,"line":3429},[270,10620,7163],{},[270,10622,10623],{"class":272,"line":3434},[270,10624,10625],{},"            self.modbus_clients[device['name']] = {\n",[270,10627,10628],{"class":272,"line":3440},[270,10629,10630],{},"                'client': client,\n",[270,10632,10633],{"class":272,"line":3446},[270,10634,10635],{},"                'config': device\n",[270,10637,10638],{"class":272,"line":3452},[270,10639,4592],{},[270,10641,10642],{"class":272,"line":3457},[270,10643,775],{"emptyLinePlaceholder":524},[270,10645,10646],{"class":272,"line":3463},[270,10647,10648],{},"        # AWS IoT MQTT connection\n",[270,10650,10651],{"class":272,"line":3469},[270,10652,10653],{},"        self._setup_mqtt()\n",[270,10655,10656],{"class":272,"line":3475},[270,10657,775],{"emptyLinePlaceholder":524},[270,10659,10660],{"class":272,"line":3480},[270,10661,10662],{},"    def _setup_mqtt(self):\n",[270,10664,10665],{"class":272,"line":3486},[270,10666,7215],{},[270,10668,10669],{"class":272,"line":3492},[270,10670,10671],{},"        aws_config = self.config['aws_iot']\n",[270,10673,10674],{"class":272,"line":3497},[270,10675,10676],{},"        cert_path = aws_config['cert_path']\n",[270,10678,10679],{"class":272,"line":3503},[270,10680,775],{"emptyLinePlaceholder":524},[270,10682,10683],{"class":272,"line":3509},[270,10684,10685],{},"        # Secure connection with TLS\n",[270,10687,10688],{"class":272,"line":3515},[270,10689,10690],{},"        self.mqtt_connection = mqtt_connection_builder.mtls_from_path(\n",[270,10692,10693],{"class":272,"line":3521},[270,10694,10695],{},"            endpoint=aws_config['endpoint'],\n",[270,10697,10698],{"class":272,"line":3527},[270,10699,10700],{},"            port=aws_config['port'],\n",[270,10702,10703],{"class":272,"line":3532},[270,10704,10705],{},"            cert_filepath=f\"{cert_path}gateway-cert.pem\",\n",[270,10707,10708],{"class":272,"line":3538},[270,10709,10710],{},"            pri_key_filepath=f\"{cert_path}gateway-private.key\",\n",[270,10712,10713],{"class":272,"line":3544},[270,10714,10715],{},"            ca_filepath=f\"{cert_path}AmazonRootCA1.pem\",\n",[270,10717,10718],{"class":272,"line":3550},[270,10719,10720],{},"            client_id=aws_config['thing_name'],\n",[270,10722,10723],{"class":272,"line":3556},[270,10724,7255],{},[270,10726,10727],{"class":272,"line":3562},[270,10728,7260],{},[270,10730,10731],{"class":272,"line":3568},[270,10732,3766],{},[270,10734,10735],{"class":272,"line":3574},[270,10736,775],{"emptyLinePlaceholder":524},[270,10738,10739],{"class":272,"line":3580},[270,10740,10741],{},"        # Connect\n",[270,10743,10744],{"class":272,"line":3586},[270,10745,10746],{},"        connect_future = self.mqtt_connection.connect()\n",[270,10748,10749],{"class":272,"line":3592},[270,10750,10751],{},"        connect_future.result()\n",[270,10753,10754],{"class":272,"line":3597},[270,10755,10756],{},"        print(f\"✓ Connected to AWS IoT Core: {aws_config['endpoint']}\")\n",[270,10758,10759],{"class":272,"line":3603},[270,10760,775],{"emptyLinePlaceholder":524},[270,10762,10763],{"class":272,"line":3609},[270,10764,10765],{},"    def read_modbus_device(self, device_name):\n",[270,10767,10768],{"class":272,"line":3615},[270,10769,10770],{},"        \"\"\"Read all registers from a Modbus device\"\"\"\n",[270,10772,10773],{"class":272,"line":3621},[270,10774,10775],{},"        device = self.modbus_clients[device_name]\n",[270,10777,10778],{"class":272,"line":3627},[270,10779,10780],{},"        client = device['client']\n",[270,10782,10783],{"class":272,"line":3633},[270,10784,10785],{},"        config = device['config']\n",[270,10787,10788],{"class":272,"line":3639},[270,10789,775],{"emptyLinePlaceholder":524},[270,10791,10792],{"class":272,"line":3645},[270,10793,10794],{},"        data = {\n",[270,10796,10797],{"class":272,"line":3651},[270,10798,10799],{},"            'device_name': device_name,\n",[270,10801,10802],{"class":272,"line":3657},[270,10803,10804],{},"            'timestamp': int(time.time() * 1000),\n",[270,10806,10807],{"class":272,"line":3663},[270,10808,10809],{},"            'values': {}\n",[270,10811,10812],{"class":272,"line":3669},[270,10813,4491],{},[270,10815,10816],{"class":272,"line":3675},[270,10817,775],{"emptyLinePlaceholder":524},[270,10819,10820],{"class":272,"line":3681},[270,10821,10822],{},"        for register in config['registers']:\n",[270,10824,10825],{"class":272,"line":3687},[270,10826,10827],{},"            try:\n",[270,10829,10830],{"class":272,"line":3693},[270,10831,10832],{},"                # Read holding register\n",[270,10834,10835],{"class":272,"line":3698},[270,10836,10837],{},"                result = client.read_holding_registers(\n",[270,10839,10840],{"class":272,"line":3704},[270,10841,10842],{},"                    address=register['address'],\n",[270,10844,10845],{"class":272,"line":3710},[270,10846,10847],{},"                    count=register['count'],\n",[270,10849,10850],{"class":272,"line":3716},[270,10851,10852],{},"                    unit=config['unit_id']\n",[270,10854,10855],{"class":272,"line":3721},[270,10856,10857],{},"                )\n",[270,10859,10860],{"class":272,"line":3727},[270,10861,775],{"emptyLinePlaceholder":524},[270,10863,10864],{"class":272,"line":3733},[270,10865,10866],{},"                if not result.isError():\n",[270,10868,10869],{"class":272,"line":3739},[270,10870,10871],{},"                    # Float conversion (IEEE 754)\n",[270,10873,10874],{"class":272,"line":3745},[270,10875,10876],{},"                    if register['type'] == 'float' and register['count'] == 2:\n",[270,10878,10879],{"class":272,"line":3751},[270,10880,10881],{},"                        raw = (result.registers[0] \u003C\u003C 16) | result.registers[1]\n",[270,10883,10884],{"class":272,"line":3757},[270,10885,10886],{},"                        value = struct.unpack('f', struct.pack('I', raw))[0]\n",[270,10888,10889],{"class":272,"line":3763},[270,10890,775],{"emptyLinePlaceholder":524},[270,10892,10893],{"class":272,"line":3769},[270,10894,10895],{},"                    data['values'][register['name']] = round(value, 3)\n",[270,10897,10898],{"class":272,"line":3774},[270,10899,775],{"emptyLinePlaceholder":524},[270,10901,10902],{"class":272,"line":3780},[270,10903,10904],{},"            except Exception as e:\n",[270,10906,10907],{"class":272,"line":3786},[270,10908,10909],{},"                print(f\"✗ Error: {device_name} - {e}\")\n",[270,10911,10912],{"class":272,"line":3792},[270,10913,10914],{},"                data['values'][register['name']] = None\n",[270,10916,10917],{"class":272,"line":7470},[270,10918,775],{"emptyLinePlaceholder":524},[270,10920,10921],{"class":272,"line":7476},[270,10922,10923],{},"        return data\n",[270,10925,10926],{"class":272,"line":7482},[270,10927,775],{"emptyLinePlaceholder":524},[270,10929,10930],{"class":272,"line":7488},[270,10931,10932],{},"    def publish_to_aws(self, device_name, data):\n",[270,10934,10935],{"class":272,"line":7494},[270,10936,7416],{},[270,10938,10939],{"class":272,"line":7500},[270,10940,10941],{},"        topic = f\"{self.config['aws_iot']['topic_prefix']}/{device_name}/data\"\n",[270,10943,10944],{"class":272,"line":7506},[270,10945,7426],{},[270,10947,10948],{"class":272,"line":7512},[270,10949,775],{"emptyLinePlaceholder":524},[270,10951,10952],{"class":272,"line":7518},[270,10953,7435],{},[270,10955,10956],{"class":272,"line":7524},[270,10957,7440],{},[270,10959,10960],{"class":272,"line":7529},[270,10961,7445],{},[270,10963,10964],{"class":272,"line":7535},[270,10965,10966],{},"            qos=mqtt.QoS.AT_LEAST_ONCE\n",[270,10968,10969],{"class":272,"line":7541},[270,10970,3766],{},[270,10972,10973],{"class":272,"line":7547},[270,10974,775],{"emptyLinePlaceholder":524},[270,10976,10977],{"class":272,"line":7552},[270,10978,10979],{},"        print(f\"→ Published to {topic}: {payload}\")\n",[270,10981,10982],{"class":272,"line":7558},[270,10983,775],{"emptyLinePlaceholder":524},[270,10985,10986],{"class":272,"line":7564},[270,10987,7532],{},[270,10989,10990],{"class":272,"line":7570},[270,10991,10992],{},"        \"\"\"Main loop: Read from Modbus, send to MQTT\"\"\"\n",[270,10994,10995],{"class":272,"line":7576},[270,10996,10997],{},"        interval = self.config['polling_interval']\n",[270,10999,11000],{"class":272,"line":7582},[270,11001,775],{"emptyLinePlaceholder":524},[270,11003,11004],{"class":272,"line":7587},[270,11005,11006],{},"        print(f\"Gateway started. Polling interval: {interval}s\")\n",[270,11008,11009],{"class":272,"line":7593},[270,11010,775],{"emptyLinePlaceholder":524},[270,11012,11013],{"class":272,"line":7599},[270,11014,7555],{},[270,11016,11017],{"class":272,"line":7605},[270,11018,7561],{},[270,11020,11021],{"class":272,"line":7610},[270,11022,11023],{},"                for device_name in self.modbus_clients.keys():\n",[270,11025,11026],{"class":272,"line":7616},[270,11027,11028],{},"                    # Read from Modbus\n",[270,11030,11031],{"class":272,"line":7622},[270,11032,11033],{},"                    data = self.read_modbus_device(device_name)\n",[270,11035,11036],{"class":272,"line":7627},[270,11037,775],{"emptyLinePlaceholder":524},[270,11039,11040],{"class":272,"line":7633},[270,11041,11042],{},"                    # Send to AWS\n",[270,11044,11045],{"class":272,"line":7638},[270,11046,11047],{},"                    self.publish_to_aws(device_name, data)\n",[270,11049,11050],{"class":272,"line":7644},[270,11051,775],{"emptyLinePlaceholder":524},[270,11053,11054],{"class":272,"line":7650},[270,11055,11056],{},"                time.sleep(interval)\n",[270,11058,11059],{"class":272,"line":7656},[270,11060,775],{"emptyLinePlaceholder":524},[270,11062,11063],{"class":272,"line":7661},[270,11064,7641],{},[270,11066,11067],{"class":272,"line":7667},[270,11068,11069],{},"            print(\"\\nStopping gateway...\")\n",[270,11071,11072],{"class":272,"line":7673},[270,11073,7653],{},[270,11075,11076],{"class":272,"line":9565},[270,11077,775],{"emptyLinePlaceholder":524},[270,11079,11080],{"class":272,"line":9571},[270,11081,7664],{},[270,11083,11084],{"class":272,"line":9577},[270,11085,11086],{},"    gateway = ModbusToMQTTGateway('/etc/iot-gateway/config.json')\n",[270,11088,11089],{"class":272,"line":9583},[270,11090,7676],{},[11,11092,11094],{"id":11093},"real-time-alarm-scenario","Real-Time Alarm Scenario",[24,11096,11098],{"id":11097},"lambda-function-for-threshold-control","Lambda Function for Threshold Control",[16,11100,11101],{},[93,11102,11103],{},[36,11104,11105],{},"alarm_handler.py",[29,11107,11109],{"className":751,"code":11108,"language":753,"meta":38,"style":38},"import json\nimport boto3\n\nsns = boto3.client('sns')\n\ndef lambda_handler(event, context):\n    # Data from IoT Core\n    device = event['device_name']\n    weight = event['values'].get('net_weight', 0)\n\n    # Threshold check\n    if weight > 5000:  # Over 5 tons\n        message = f\"ALARM: {device} - Weight limit exceeded: {weight} kg\"\n\n        sns.publish(\n            TopicArn='arn:aws:sns:eu-west-1:123456789:factory-alarms',\n            Subject='Tank Capacity Alarm',\n            Message=message\n        )\n\n        return {'statusCode': 200, 'body': 'Alarm sent'}\n\n    return {'statusCode': 200, 'body': 'Normal'}\n",[36,11110,11111,11115,11119,11123,11127,11131,11135,11140,11145,11150,11154,11159,11164,11169,11173,11177,11182,11187,11192,11196,11200,11205,11209],{"__ignoreMap":38},[270,11112,11113],{"class":272,"line":273},[270,11114,3319],{},[270,11116,11117],{"class":272,"line":279},[270,11118,3314],{},[270,11120,11121],{"class":272,"line":285},[270,11122,775],{"emptyLinePlaceholder":524},[270,11124,11125],{"class":272,"line":291},[270,11126,7763],{},[270,11128,11129],{"class":272,"line":297},[270,11130,775],{"emptyLinePlaceholder":524},[270,11132,11133],{"class":272,"line":303},[270,11134,3347],{},[270,11136,11137],{"class":272,"line":515},[270,11138,11139],{},"    # Data from IoT Core\n",[270,11141,11142],{"class":272,"line":793},[270,11143,11144],{},"    device = event['device_name']\n",[270,11146,11147],{"class":272,"line":799},[270,11148,11149],{},"    weight = event['values'].get('net_weight', 0)\n",[270,11151,11152],{"class":272,"line":805},[270,11153,775],{"emptyLinePlaceholder":524},[270,11155,11156],{"class":272,"line":2120},[270,11157,11158],{},"    # Threshold check\n",[270,11160,11161],{"class":272,"line":2126},[270,11162,11163],{},"    if weight > 5000:  # Over 5 tons\n",[270,11165,11166],{"class":272,"line":2132},[270,11167,11168],{},"        message = f\"ALARM: {device} - Weight limit exceeded: {weight} kg\"\n",[270,11170,11171],{"class":272,"line":3375},[270,11172,775],{"emptyLinePlaceholder":524},[270,11174,11175],{"class":272,"line":3381},[270,11176,3742],{},[270,11178,11179],{"class":272,"line":3387},[270,11180,11181],{},"            TopicArn='arn:aws:sns:eu-west-1:123456789:factory-alarms',\n",[270,11183,11184],{"class":272,"line":3393},[270,11185,11186],{},"            Subject='Tank Capacity Alarm',\n",[270,11188,11189],{"class":272,"line":3399},[270,11190,11191],{},"            Message=message\n",[270,11193,11194],{"class":272,"line":3405},[270,11195,3766],{},[270,11197,11198],{"class":272,"line":3411},[270,11199,775],{"emptyLinePlaceholder":524},[270,11201,11202],{"class":272,"line":3417},[270,11203,11204],{},"        return {'statusCode': 200, 'body': 'Alarm sent'}\n",[270,11206,11207],{"class":272,"line":3423},[270,11208,775],{"emptyLinePlaceholder":524},[270,11210,11211],{"class":272,"line":3429},[270,11212,11213],{},"    return {'statusCode': 200, 'body': 'Normal'}\n",[11,11215,11217],{"id":11216},"cost-analysis","Cost Analysis",[24,11219,11221],{"id":11220},"aws-iot-core-pricing-eu-west-1","AWS IoT Core Pricing (eu-west-1)",[636,11223,11224,11237],{},[639,11225,11226],{},[642,11227,11228,11231,11234],{},[645,11229,11230],{},"Component",[645,11232,11233],{},"Price",[645,11235,11236],{},"Monthly Cost*",[655,11238,11239,11252,11265,11278,11291,11304],{},[642,11240,11241,11246,11249],{},[660,11242,11243],{},[93,11244,11245],{},"Connectivity",[660,11247,11248],{},"$0.08 / million connection-minutes",[660,11250,11251],{},"$3.45 (2 devices, 24/7)",[642,11253,11254,11259,11262],{},[660,11255,11256],{},[93,11257,11258],{},"Messaging",[660,11260,11261],{},"$1.00 / million messages",[660,11263,11264],{},"$2.59 (1s polling, 2 devices)",[642,11266,11267,11272,11275],{},[660,11268,11269],{},[93,11270,11271],{},"Rule Engine",[660,11273,11274],{},"$0.15 / million rules",[660,11276,11277],{},"$0.38",[642,11279,11280,11285,11288],{},[660,11281,11282],{},[93,11283,11284],{},"Timestream Write",[660,11286,11287],{},"$0.50 / million writes",[660,11289,11290],{},"$1.30",[642,11292,11293,11298,11301],{},[660,11294,11295],{},[93,11296,11297],{},"Timestream Storage",[660,11299,11300],{},"$0.03 / GB-hour",[660,11302,11303],{},"$21.60 (30GB)",[642,11305,11306,11311,11313],{},[660,11307,11308],{},[93,11309,11310],{},"TOTAL",[660,11312],{},[660,11314,11315],{},[93,11316,11317],{},"~$29/month",[16,11319,11320],{},"*2 devices, 1 second polling, 30 days retention",[11,11322,444],{"id":443},[16,11324,1718,11325,467,11327,11329,11330,11332,11333,11335],{},[463,11326,1360],{"href":1613},[463,11328,2840],{"href":1723}," products can easily connect to AWS IoT Core via ",[93,11331,10247],{}," thanks to ",[93,11334,6004],{}," support. This enables:",[16,11337,11338,11339,11341,11342,11344,11345,11347],{},"✅ Real-time data monitoring (Grafana/QuickSight)",[2353,11340],{},"\n✅ Long-term data storage (Timestream)",[2353,11343],{},"\n✅ Predictive maintenance (AI/ML models)",[2353,11346],{},"\n✅ Remote alarms and notifications",[16,11349,11350,11351,6180,11354,472],{},"For more information about our ",[463,11352,11353],{"href":2634},"Cloud & IoT Data Collection Solutions",[463,11355,11356],{"href":1628},"contact us",[24,11358,2964],{"id":2963},[40,11360,11361,11365,11369,11373],{},[43,11362,11363],{},[463,11364,2983],{"href":2634},[43,11366,11367],{},[463,11368,466],{"href":1613},[43,11370,11371],{},[463,11372,471],{"href":1723},[43,11374,11375],{},[463,11376,2465],{"href":2464},[477,11378,11379],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":38,"searchDepth":279,"depth":279,"links":11381},[11382,11383,11384,11387,11391,11394,11397,11400],{"id":13,"depth":279,"text":14},{"id":10264,"depth":279,"text":10265},{"id":10274,"depth":279,"text":10275,"children":11385},[11386],{"id":10301,"depth":285,"text":10302},{"id":10342,"depth":279,"text":10343,"children":11388},[11389,11390],{"id":10346,"depth":285,"text":10347},{"id":10423,"depth":285,"text":10424},{"id":10502,"depth":279,"text":10503,"children":11392},[11393],{"id":10506,"depth":285,"text":10507},{"id":11093,"depth":279,"text":11094,"children":11395},[11396],{"id":11097,"depth":285,"text":11098},{"id":11216,"depth":279,"text":11217,"children":11398},[11399],{"id":11220,"depth":285,"text":11221},{"id":443,"depth":279,"text":444,"children":11401},[11402],{"id":2963,"depth":285,"text":2964},"Transfer of data collected via Modbus from ZMA and GDT devices to AWS IoT Core cloud platform via IoT gateway using MQTT protocol.",{"date":3011,"author":514,"readTime":2126,"tags":11405},[2341,6010,1360,2840,11406,11407,7985],"Modbus Gateway","Cloud IoT",{"title":10225,"description":11403},"en/blog/industrial-data-collection-with-aws-iot-core","SqqbdRvhQPk0TAF2BuutIGnJB2ehA_8Mioj6rykY5Po",{"id":11412,"title":11413,"body":11414,"description":13059,"extension":511,"meta":13060,"navigation":524,"path":2387,"seo":13066,"stem":13067,"__hash__":13068},"en_blog/en/blog/industrial-iot-automation-with-n8n.md","Industrial IoT Automation with n8n: No-Code Workflow Integration",{"type":8,"value":11415,"toc":13016},[11416,11418,11433,11441,11445,11450,11454,11484,11488,11578,11580,11586,11590,11594,11767,11771,11801,11805,11807,11810,11814,11819,11854,11859,11865,11869,11975,11979,12049,12053,12130,12134,12136,12139,12143,12149,12153,12256,12260,12323,12327,12398,12402,12404,12407,12410,12416,12420,12478,12483,12566,12570,12660,12664,12731,12735,12739,12860,12864,12868,12921,12925,12930,12950,12952,12961,12982,12993,12995,13013],[11,11417,14],{"id":13},[16,11419,11420,11421,11424,11425,11428,11429,11432],{},"In industrial facilities, managing data from dozens of sensors can become complex. Alerting, reporting, ERP system integration – all require separate development effort. ",[93,11422,11423],{},"n8n",", an open-source ",[93,11426,11427],{},"workflow automation"," platform, simplifies these processes with a visual ",[93,11430,11431],{},"no-code"," interface.",[16,11434,11435,11436,467,11438,11440],{},"In this article, we examine how to automate data flows from our ",[463,11437,466],{"href":1613},[463,11439,471],{"href":1723}," devices using n8n, without writing code.",[11,11442,11444],{"id":11443},"what-is-n8n","What is n8n?",[16,11446,11447,11449],{},[93,11448,11423],{}," (nodemation) is an automation platform that connects applications and services. The open-source alternative to Zapier/Make.",[24,11451,11453],{"id":11452},"key-features","Key Features",[16,11455,5091,11456,11459,11460,5098,11462,11465,11466,5098,11468,11471,11472,5098,11474,11477,11478,5098,11480,11483],{},[93,11457,11458],{},"Open Source:"," Self-hosted, full control",[2353,11461],{},[93,11463,11464],{},"Visual Interface:"," Workflow design with drag & drop",[2353,11467],{},[93,11469,11470],{},"300+ Integrations:"," MQTT, HTTP, Email, Slack, SAP, databases",[2353,11473],{},[93,11475,11476],{},"Code Support:"," JavaScript when needed",[2353,11479],{},[93,11481,11482],{},"Low Latency:"," Real-time triggers",[24,11485,11487],{"id":11486},"n8n-vs-alternatives","n8n vs Alternatives",[636,11489,11490,11504],{},[639,11491,11492],{},[642,11493,11494,11496,11498,11501],{},[645,11495,647],{},[645,11497,11423],{},[645,11499,11500],{},"Zapier",[645,11502,11503],{},"Make (Integromat)",[655,11505,11506,11521,11533,11548,11562],{},[642,11507,11508,11513,11516,11519],{},[660,11509,11510],{},[93,11511,11512],{},"Open Source",[660,11514,11515],{},"✅ Yes",[660,11517,11518],{},"❌ No",[660,11520,11518],{},[642,11522,11523,11527,11529,11531],{},[660,11524,11525],{},[93,11526,2210],{},[660,11528,11515],{},[660,11530,11518],{},[660,11532,11518],{},[642,11534,11535,11540,11543,11545],{},[660,11536,11537],{},[93,11538,11539],{},"MQTT Support",[660,11541,11542],{},"✅ Native",[660,11544,11518],{},[660,11546,11547],{},"⚠️ Limited",[642,11549,11550,11555,11557,11560],{},[660,11551,11552],{},[93,11553,11554],{},"Unlimited Workflows",[660,11556,11515],{},[660,11558,11559],{},"❌ Paid plans",[660,11561,11559],{},[642,11563,11564,11569,11572,11575],{},[660,11565,11566],{},[93,11567,11568],{},"Cost (1000 ops/month)",[660,11570,11571],{},"Free",[660,11573,11574],{},"$19.99",[660,11576,11577],{},"$9.00",[11,11579,3280],{"id":3279},[29,11581,11584],{"className":11582,"code":11583,"language":34},[32],"┌───────────────────────────────────────────────────┐\n│                Factory Network                    │\n│                                                   │\n│  ┌─────────┐      MQTT       ┌──────────────┐   │\n│  │ ZMA/GDT │─────────────────►│              │   │\n│  │ Devices │                  │  MQTT Broker │   │\n│  └─────────┘                  │  (Mosquitto) │   │\n│                               └──────┬───────┘   │\n│                                      │            │\n│                               ┌──────▼───────┐   │\n│                               │     n8n      │   │\n│                               │  Automation  │   │\n│                               │   Server     │   │\n│                               └──┬─────┬─────┘   │\n└──────────────────────────────────┼─────┼─────────┘\n                                   │     │\n                    ┌──────────────┘     └─────────────┐\n                    │                                  │\n            ┌───────▼────────┐              ┌──────────▼────────┐\n            │  Email / Slack │              │   ERP / Database  │\n            │  Notifications │              │   (SAP, REST API) │\n            └────────────────┘              └───────────────────┘\n",[36,11585,11583],{"__ignoreMap":38},[11,11587,11589],{"id":11588},"n8n-installation-docker","n8n Installation (Docker)",[24,11591,11593],{"id":11592},"docker-composeyml","docker-compose.yml",[29,11595,11597],{"className":1905,"code":11596,"language":1907,"meta":38,"style":38},"version: '3.8'\n\nservices:\n  n8n:\n    image: n8nio/n8n:latest\n    container_name: n8n\n    restart: always\n    ports:\n      - '5678:5678'\n    environment:\n      - N8N_BASIC_AUTH_ACTIVE=true\n      - N8N_BASIC_AUTH_USER=admin\n      - N8N_BASIC_AUTH_PASSWORD=secure_password_123\n      - N8N_HOST=n8n.factory.local\n      - WEBHOOK_URL=http://n8n.factory.local:5678\n      - N8N_PROTOCOL=http\n      - NODE_ENV=production\n    volumes:\n      - n8n_data:/home/node/.n8n\n      - /var/run/docker.sock:/var/run/docker.sock\n\nvolumes:\n  n8n_data:\n",[36,11598,11599,11609,11613,11620,11627,11637,11647,11657,11664,11672,11679,11686,11693,11700,11707,11714,11721,11728,11735,11742,11749,11753,11760],{"__ignoreMap":38},[270,11600,11601,11604,11606],{"class":272,"line":273},[270,11602,11603],{"class":1914},"version",[270,11605,1927],{"class":1918},[270,11607,11608],{"class":1930},"'3.8'\n",[270,11610,11611],{"class":272,"line":279},[270,11612,775],{"emptyLinePlaceholder":524},[270,11614,11615,11618],{"class":272,"line":285},[270,11616,11617],{"class":1914},"services",[270,11619,1919],{"class":1918},[270,11621,11622,11625],{"class":272,"line":291},[270,11623,11624],{"class":1914},"  n8n",[270,11626,1919],{"class":1918},[270,11628,11629,11632,11634],{"class":272,"line":297},[270,11630,11631],{"class":1914},"    image",[270,11633,1927],{"class":1918},[270,11635,11636],{"class":1930},"n8nio/n8n:latest\n",[270,11638,11639,11642,11644],{"class":272,"line":303},[270,11640,11641],{"class":1914},"    container_name",[270,11643,1927],{"class":1918},[270,11645,11646],{"class":1930},"n8n\n",[270,11648,11649,11652,11654],{"class":272,"line":515},[270,11650,11651],{"class":1914},"    restart",[270,11653,1927],{"class":1918},[270,11655,11656],{"class":1930},"always\n",[270,11658,11659,11662],{"class":272,"line":793},[270,11660,11661],{"class":1914},"    ports",[270,11663,1919],{"class":1918},[270,11665,11666,11669],{"class":272,"line":799},[270,11667,11668],{"class":1918},"      - ",[270,11670,11671],{"class":1930},"'5678:5678'\n",[270,11673,11674,11677],{"class":272,"line":805},[270,11675,11676],{"class":1914},"    environment",[270,11678,1919],{"class":1918},[270,11680,11681,11683],{"class":272,"line":2120},[270,11682,11668],{"class":1918},[270,11684,11685],{"class":1930},"N8N_BASIC_AUTH_ACTIVE=true\n",[270,11687,11688,11690],{"class":272,"line":2126},[270,11689,11668],{"class":1918},[270,11691,11692],{"class":1930},"N8N_BASIC_AUTH_USER=admin\n",[270,11694,11695,11697],{"class":272,"line":2132},[270,11696,11668],{"class":1918},[270,11698,11699],{"class":1930},"N8N_BASIC_AUTH_PASSWORD=secure_password_123\n",[270,11701,11702,11704],{"class":272,"line":3375},[270,11703,11668],{"class":1918},[270,11705,11706],{"class":1930},"N8N_HOST=n8n.factory.local\n",[270,11708,11709,11711],{"class":272,"line":3381},[270,11710,11668],{"class":1918},[270,11712,11713],{"class":1930},"WEBHOOK_URL=http://n8n.factory.local:5678\n",[270,11715,11716,11718],{"class":272,"line":3387},[270,11717,11668],{"class":1918},[270,11719,11720],{"class":1930},"N8N_PROTOCOL=http\n",[270,11722,11723,11725],{"class":272,"line":3393},[270,11724,11668],{"class":1918},[270,11726,11727],{"class":1930},"NODE_ENV=production\n",[270,11729,11730,11733],{"class":272,"line":3399},[270,11731,11732],{"class":1914},"    volumes",[270,11734,1919],{"class":1918},[270,11736,11737,11739],{"class":272,"line":3405},[270,11738,11668],{"class":1918},[270,11740,11741],{"class":1930},"n8n_data:/home/node/.n8n\n",[270,11743,11744,11746],{"class":272,"line":3411},[270,11745,11668],{"class":1918},[270,11747,11748],{"class":1930},"/var/run/docker.sock:/var/run/docker.sock\n",[270,11750,11751],{"class":272,"line":3417},[270,11752,775],{"emptyLinePlaceholder":524},[270,11754,11755,11758],{"class":272,"line":3423},[270,11756,11757],{"class":1914},"volumes",[270,11759,1919],{"class":1918},[270,11761,11762,11765],{"class":272,"line":3429},[270,11763,11764],{"class":1914},"  n8n_data",[270,11766,1919],{"class":1918},[24,11768,11770],{"id":11769},"start-services","Start Services",[29,11772,11774],{"className":1993,"code":11773,"language":1995,"meta":38,"style":38},"docker-compose up -d\n\n# Access web interface\n# http://localhost:5678\n",[36,11775,11776,11787,11791,11796],{"__ignoreMap":38},[270,11777,11778,11781,11784],{"class":272,"line":273},[270,11779,11780],{"class":2008},"docker-compose",[270,11782,11783],{"class":1930}," up",[270,11785,11786],{"class":2053}," -d\n",[270,11788,11789],{"class":272,"line":279},[270,11790,775],{"emptyLinePlaceholder":524},[270,11792,11793],{"class":272,"line":285},[270,11794,11795],{"class":2002},"# Access web interface\n",[270,11797,11798],{"class":272,"line":291},[270,11799,11800],{"class":2002},"# http://localhost:5678\n",[11,11802,11804],{"id":11803},"workflow-1-tank-weight-alert-system","Workflow 1: Tank Weight Alert System",[24,11806,3294],{"id":3293},[16,11808,11809],{},"Send email and Slack notification when milk tank weight exceeds 90% capacity.",[24,11811,11813],{"id":11812},"n8n-workflow-configuration","n8n Workflow Configuration",[16,11815,11816],{},[93,11817,11818],{},"Nodes:",[176,11820,11821,11830,11836,11842,11848],{},[43,11822,11823,11826,11827],{},[93,11824,11825],{},"MQTT Trigger"," → Listen to topic ",[36,11828,11829],{},"factory/tank/+/weight",[43,11831,11832,11835],{},[93,11833,11834],{},"Function"," → Calculate fill percentage",[43,11837,11838,11841],{},[93,11839,11840],{},"IF"," → Check if >90%",[43,11843,11844,11847],{},[93,11845,11846],{},"Email"," → Send warning email",[43,11849,11850,11853],{},[93,11851,11852],{},"Slack"," → Post to #production channel",[16,11855,11856],{},[93,11857,11858],{},"Visual Workflow:",[29,11860,11863],{"className":11861,"code":11862,"language":34},[32],"┌──────────────┐\n│ MQTT Trigger │\n│ Topic:       │\n│ factory/tank │\n│    /+/weight │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│   Function   │\n│ Calculate %  │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│      IF      │\n│ weight > 90% │\n└──┬───────┬───┘\n   │       │\n   │ YES   │ NO\n   │       └──► (End)\n   ▼\n┌──────────────┐\n│    Email     │\n│   To: ops@   │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│    Slack     │\n│ #production  │\n└──────────────┘\n",[36,11864,11862],{"__ignoreMap":38},[24,11866,11868],{"id":11867},"mqtt-trigger-node-configuration","MQTT Trigger Node Configuration",[29,11870,11872],{"className":3803,"code":11871,"language":3805,"meta":38,"style":38},"{\n  \"protocol\": \"mqtt\",\n  \"host\": \"192.168.1.10\",\n  \"port\": 1883,\n  \"topics\": \"factory/tank/+/weight\",\n  \"qos\": 1,\n  \"credentials\": {\n    \"username\": \"mqtt_user\",\n    \"password\": \"mqtt_password\"\n  }\n}\n",[36,11873,11874,11878,11890,11902,11914,11926,11938,11945,11957,11967,11971],{"__ignoreMap":38},[270,11875,11876],{"class":272,"line":273},[270,11877,3812],{"class":1918},[270,11879,11880,11883,11885,11888],{"class":272,"line":279},[270,11881,11882],{"class":2053},"  \"protocol\"",[270,11884,1927],{"class":1918},[270,11886,11887],{"class":1930},"\"mqtt\"",[270,11889,3825],{"class":1918},[270,11891,11892,11895,11897,11900],{"class":272,"line":285},[270,11893,11894],{"class":2053},"  \"host\"",[270,11896,1927],{"class":1918},[270,11898,11899],{"class":1930},"\"192.168.1.10\"",[270,11901,3825],{"class":1918},[270,11903,11904,11907,11909,11912],{"class":272,"line":291},[270,11905,11906],{"class":2053},"  \"port\"",[270,11908,1927],{"class":1918},[270,11910,11911],{"class":2053},"1883",[270,11913,3825],{"class":1918},[270,11915,11916,11919,11921,11924],{"class":272,"line":297},[270,11917,11918],{"class":2053},"  \"topics\"",[270,11920,1927],{"class":1918},[270,11922,11923],{"class":1930},"\"factory/tank/+/weight\"",[270,11925,3825],{"class":1918},[270,11927,11928,11931,11933,11936],{"class":272,"line":303},[270,11929,11930],{"class":2053},"  \"qos\"",[270,11932,1927],{"class":1918},[270,11934,11935],{"class":2053},"1",[270,11937,3825],{"class":1918},[270,11939,11940,11943],{"class":272,"line":515},[270,11941,11942],{"class":2053},"  \"credentials\"",[270,11944,6468],{"class":1918},[270,11946,11947,11950,11952,11955],{"class":272,"line":793},[270,11948,11949],{"class":2053},"    \"username\"",[270,11951,1927],{"class":1918},[270,11953,11954],{"class":1930},"\"mqtt_user\"",[270,11956,3825],{"class":1918},[270,11958,11959,11962,11964],{"class":272,"line":799},[270,11960,11961],{"class":2053},"    \"password\"",[270,11963,1927],{"class":1918},[270,11965,11966],{"class":1930},"\"mqtt_password\"\n",[270,11968,11969],{"class":272,"line":805},[270,11970,6564],{"class":1918},[270,11972,11973],{"class":272,"line":2120},[270,11974,2129],{"class":1918},[24,11976,11978],{"id":11977},"function-node-calculate-fill","Function Node (Calculate Fill %)",[29,11980,11982],{"className":2064,"code":11981,"language":2066,"meta":38,"style":38},"// Received MQTT message structure:\n// { \"tank_id\": 1, \"weight\": 4520.5, \"capacity\": 5000 }\n\nconst tankData = items[0].json\n\nconst fillPercent = (tankData.weight / tankData.capacity) * 100\n\nreturn {\n  json: {\n    ...tankData,\n    fill_percent: fillPercent,\n    alert_level: fillPercent > 90 ? 'HIGH' : 'NORMAL',\n  },\n}\n",[36,11983,11984,11989,11994,11998,12003,12007,12012,12016,12021,12026,12031,12036,12041,12045],{"__ignoreMap":38},[270,11985,11986],{"class":272,"line":273},[270,11987,11988],{},"// Received MQTT message structure:\n",[270,11990,11991],{"class":272,"line":279},[270,11992,11993],{},"// { \"tank_id\": 1, \"weight\": 4520.5, \"capacity\": 5000 }\n",[270,11995,11996],{"class":272,"line":285},[270,11997,775],{"emptyLinePlaceholder":524},[270,11999,12000],{"class":272,"line":291},[270,12001,12002],{},"const tankData = items[0].json\n",[270,12004,12005],{"class":272,"line":297},[270,12006,775],{"emptyLinePlaceholder":524},[270,12008,12009],{"class":272,"line":303},[270,12010,12011],{},"const fillPercent = (tankData.weight / tankData.capacity) * 100\n",[270,12013,12014],{"class":272,"line":515},[270,12015,775],{"emptyLinePlaceholder":524},[270,12017,12018],{"class":272,"line":793},[270,12019,12020],{},"return {\n",[270,12022,12023],{"class":272,"line":799},[270,12024,12025],{},"  json: {\n",[270,12027,12028],{"class":272,"line":805},[270,12029,12030],{},"    ...tankData,\n",[270,12032,12033],{"class":272,"line":2120},[270,12034,12035],{},"    fill_percent: fillPercent,\n",[270,12037,12038],{"class":272,"line":2126},[270,12039,12040],{},"    alert_level: fillPercent > 90 ? 'HIGH' : 'NORMAL',\n",[270,12042,12043],{"class":272,"line":2132},[270,12044,2098],{},[270,12046,12047],{"class":272,"line":3375},[270,12048,2129],{},[24,12050,12052],{"id":12051},"email-node-configuration","Email Node Configuration",[29,12054,12056],{"className":3803,"code":12055,"language":3805,"meta":38,"style":38},"{\n  \"fromEmail\": \"alerts@factory.com\",\n  \"toEmail\": \"operations@factory.com\",\n  \"subject\": \"⚠️ Tank {{$json.tank_id}} Capacity Alert\",\n  \"text\": \"Tank {{$json.tank_id}} is {{$json.fill_percent}}% full ({{$json.weight}} kg / {{$json.capacity}} kg).\\n\\nAction required: Prepare for milk collection.\",\n  \"html\": \"\u003Ch2>Tank Capacity Alert\u003C/h2>\u003Cp>Tank \u003Cstrong>{{$json.tank_id}}\u003C/strong>\u003C/p>\u003Cp>Fill Level: \u003Cstrong style='color:red'>{{$json.fill_percent}}%\u003C/strong>\u003C/p>\"\n}\n",[36,12057,12058,12062,12074,12086,12098,12116,12126],{"__ignoreMap":38},[270,12059,12060],{"class":272,"line":273},[270,12061,3812],{"class":1918},[270,12063,12064,12067,12069,12072],{"class":272,"line":279},[270,12065,12066],{"class":2053},"  \"fromEmail\"",[270,12068,1927],{"class":1918},[270,12070,12071],{"class":1930},"\"alerts@factory.com\"",[270,12073,3825],{"class":1918},[270,12075,12076,12079,12081,12084],{"class":272,"line":285},[270,12077,12078],{"class":2053},"  \"toEmail\"",[270,12080,1927],{"class":1918},[270,12082,12083],{"class":1930},"\"operations@factory.com\"",[270,12085,3825],{"class":1918},[270,12087,12088,12091,12093,12096],{"class":272,"line":291},[270,12089,12090],{"class":2053},"  \"subject\"",[270,12092,1927],{"class":1918},[270,12094,12095],{"class":1930},"\"⚠️ Tank {{$json.tank_id}} Capacity Alert\"",[270,12097,3825],{"class":1918},[270,12099,12100,12103,12105,12108,12111,12114],{"class":272,"line":297},[270,12101,12102],{"class":2053},"  \"text\"",[270,12104,1927],{"class":1918},[270,12106,12107],{"class":1930},"\"Tank {{$json.tank_id}} is {{$json.fill_percent}}% full ({{$json.weight}} kg / {{$json.capacity}} kg).",[270,12109,12110],{"class":2053},"\\n\\n",[270,12112,12113],{"class":1930},"Action required: Prepare for milk collection.\"",[270,12115,3825],{"class":1918},[270,12117,12118,12121,12123],{"class":272,"line":303},[270,12119,12120],{"class":2053},"  \"html\"",[270,12122,1927],{"class":1918},[270,12124,12125],{"class":1930},"\"\u003Ch2>Tank Capacity Alert\u003C/h2>\u003Cp>Tank \u003Cstrong>{{$json.tank_id}}\u003C/strong>\u003C/p>\u003Cp>Fill Level: \u003Cstrong style='color:red'>{{$json.fill_percent}}%\u003C/strong>\u003C/p>\"\n",[270,12127,12128],{"class":272,"line":515},[270,12129,2129],{"class":1918},[11,12131,12133],{"id":12132},"workflow-2-daily-production-report","Workflow 2: Daily Production Report",[24,12135,3294],{"id":3894},[16,12137,12138],{},"Generate Excel report with yesterday's all tank data and email every morning at 08:00.",[24,12140,12142],{"id":12141},"workflow","Workflow",[29,12144,12147],{"className":12145,"code":12146,"language":34},[32],"┌──────────────┐\n│   Schedule   │\n│ Cron: 0 8 ** │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│   HTTP Req   │\n│ GET /api/    │\n│ tank_data    │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│ Function     │\n│ Format data  │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│ Spreadsheet  │\n│ Create Excel │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│    Email     │\n│ + Attachment │\n└──────────────┘\n",[36,12148,12146],{"__ignoreMap":38},[24,12150,12152],{"id":12151},"http-request-node-get-data","HTTP Request Node (Get Data)",[29,12154,12156],{"className":3803,"code":12155,"language":3805,"meta":38,"style":38},"{\n  \"method\": \"GET\",\n  \"url\": \"http://api.factory.local/v1/tank_data\",\n  \"qs\": {\n    \"date\": \"{{$now.minus({days: 1}).toFormat('yyyy-MM-dd')}}\",\n    \"format\": \"json\"\n  },\n  \"authentication\": \"headerAuth\",\n  \"headers\": {\n    \"Authorization\": \"Bearer {{$credentials.apiToken}}\"\n  }\n}\n",[36,12157,12158,12162,12174,12186,12193,12205,12215,12219,12231,12238,12248,12252],{"__ignoreMap":38},[270,12159,12160],{"class":272,"line":273},[270,12161,3812],{"class":1918},[270,12163,12164,12167,12169,12172],{"class":272,"line":279},[270,12165,12166],{"class":2053},"  \"method\"",[270,12168,1927],{"class":1918},[270,12170,12171],{"class":1930},"\"GET\"",[270,12173,3825],{"class":1918},[270,12175,12176,12179,12181,12184],{"class":272,"line":285},[270,12177,12178],{"class":2053},"  \"url\"",[270,12180,1927],{"class":1918},[270,12182,12183],{"class":1930},"\"http://api.factory.local/v1/tank_data\"",[270,12185,3825],{"class":1918},[270,12187,12188,12191],{"class":272,"line":291},[270,12189,12190],{"class":2053},"  \"qs\"",[270,12192,6468],{"class":1918},[270,12194,12195,12198,12200,12203],{"class":272,"line":297},[270,12196,12197],{"class":2053},"    \"date\"",[270,12199,1927],{"class":1918},[270,12201,12202],{"class":1930},"\"{{$now.minus({days: 1}).toFormat('yyyy-MM-dd')}}\"",[270,12204,3825],{"class":1918},[270,12206,12207,12210,12212],{"class":272,"line":303},[270,12208,12209],{"class":2053},"    \"format\"",[270,12211,1927],{"class":1918},[270,12213,12214],{"class":1930},"\"json\"\n",[270,12216,12217],{"class":272,"line":515},[270,12218,2098],{"class":1918},[270,12220,12221,12224,12226,12229],{"class":272,"line":793},[270,12222,12223],{"class":2053},"  \"authentication\"",[270,12225,1927],{"class":1918},[270,12227,12228],{"class":1930},"\"headerAuth\"",[270,12230,3825],{"class":1918},[270,12232,12233,12236],{"class":272,"line":799},[270,12234,12235],{"class":2053},"  \"headers\"",[270,12237,6468],{"class":1918},[270,12239,12240,12243,12245],{"class":272,"line":805},[270,12241,12242],{"class":2053},"    \"Authorization\"",[270,12244,1927],{"class":1918},[270,12246,12247],{"class":1930},"\"Bearer {{$credentials.apiToken}}\"\n",[270,12249,12250],{"class":272,"line":2120},[270,12251,6564],{"class":1918},[270,12253,12254],{"class":272,"line":2126},[270,12255,2129],{"class":1918},[24,12257,12259],{"id":12258},"function-node-format-for-excel","Function Node (Format for Excel)",[29,12261,12263],{"className":2064,"code":12262,"language":2066,"meta":38,"style":38},"// Transform API response to Excel-friendly format\nconst rawData = items[0].json.data\n\nconst formattedData = rawData.map(record => ({\n  'Tank ID': record.tank_id,\n  Timestamp: record.timestamp,\n  'Weight (kg)': record.weight,\n  'Fill %': Math.round(record.fill_percent),\n  Status: record.status,\n}))\n\nreturn formattedData.map(row => ({ json: row }))\n",[36,12264,12265,12270,12275,12279,12284,12289,12294,12299,12304,12309,12314,12318],{"__ignoreMap":38},[270,12266,12267],{"class":272,"line":273},[270,12268,12269],{},"// Transform API response to Excel-friendly format\n",[270,12271,12272],{"class":272,"line":279},[270,12273,12274],{},"const rawData = items[0].json.data\n",[270,12276,12277],{"class":272,"line":285},[270,12278,775],{"emptyLinePlaceholder":524},[270,12280,12281],{"class":272,"line":291},[270,12282,12283],{},"const formattedData = rawData.map(record => ({\n",[270,12285,12286],{"class":272,"line":297},[270,12287,12288],{},"  'Tank ID': record.tank_id,\n",[270,12290,12291],{"class":272,"line":303},[270,12292,12293],{},"  Timestamp: record.timestamp,\n",[270,12295,12296],{"class":272,"line":515},[270,12297,12298],{},"  'Weight (kg)': record.weight,\n",[270,12300,12301],{"class":272,"line":793},[270,12302,12303],{},"  'Fill %': Math.round(record.fill_percent),\n",[270,12305,12306],{"class":272,"line":799},[270,12307,12308],{},"  Status: record.status,\n",[270,12310,12311],{"class":272,"line":805},[270,12312,12313],{},"}))\n",[270,12315,12316],{"class":272,"line":2120},[270,12317,775],{"emptyLinePlaceholder":524},[270,12319,12320],{"class":272,"line":2126},[270,12321,12322],{},"return formattedData.map(row => ({ json: row }))\n",[24,12324,12326],{"id":12325},"spreadsheet-node-configuration","Spreadsheet Node Configuration",[29,12328,12330],{"className":3803,"code":12329,"language":3805,"meta":38,"style":38},"{\n  \"operation\": \"toFile\",\n  \"fileFormat\": \"xlsx\",\n  \"fileName\": \"Daily_Production_Report_{{$now.toFormat('yyyy-MM-dd')}}.xlsx\",\n  \"sheetName\": \"Tank Data\",\n  \"headerRow\": true\n}\n",[36,12331,12332,12336,12348,12360,12372,12384,12394],{"__ignoreMap":38},[270,12333,12334],{"class":272,"line":273},[270,12335,3812],{"class":1918},[270,12337,12338,12341,12343,12346],{"class":272,"line":279},[270,12339,12340],{"class":2053},"  \"operation\"",[270,12342,1927],{"class":1918},[270,12344,12345],{"class":1930},"\"toFile\"",[270,12347,3825],{"class":1918},[270,12349,12350,12353,12355,12358],{"class":272,"line":285},[270,12351,12352],{"class":2053},"  \"fileFormat\"",[270,12354,1927],{"class":1918},[270,12356,12357],{"class":1930},"\"xlsx\"",[270,12359,3825],{"class":1918},[270,12361,12362,12365,12367,12370],{"class":272,"line":291},[270,12363,12364],{"class":2053},"  \"fileName\"",[270,12366,1927],{"class":1918},[270,12368,12369],{"class":1930},"\"Daily_Production_Report_{{$now.toFormat('yyyy-MM-dd')}}.xlsx\"",[270,12371,3825],{"class":1918},[270,12373,12374,12377,12379,12382],{"class":272,"line":297},[270,12375,12376],{"class":2053},"  \"sheetName\"",[270,12378,1927],{"class":1918},[270,12380,12381],{"class":1930},"\"Tank Data\"",[270,12383,3825],{"class":1918},[270,12385,12386,12389,12391],{"class":272,"line":303},[270,12387,12388],{"class":2053},"  \"headerRow\"",[270,12390,1927],{"class":1918},[270,12392,12393],{"class":2053},"true\n",[270,12395,12396],{"class":272,"line":515},[270,12397,2129],{"class":1918},[11,12399,12401],{"id":12400},"workflow-3-erp-system-integration","Workflow 3: ERP System Integration",[24,12403,3294],{"id":4205},[16,12405,12406],{},"When GDT weighing is complete, automatically create production record in SAP ERP system.",[24,12408,12142],{"id":12409},"workflow-1",[29,12411,12414],{"className":12412,"code":12413,"language":34},[32],"┌──────────────┐\n│    Webhook   │\n│ /weighing-   │\n│  complete    │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│   Function   │\n│ Map to SAP   │\n│   format     │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│  HTTP Req    │\n│ POST SAP API │\n│ /production  │\n└──────┬───────┘\n       │\n       ▼\n┌──────────────┐\n│      IF      │\n│   Success?   │\n└──┬───────┬───┘\n   │       │\n  YES      NO\n   │       │\n   ▼       ▼\n┌─────┐ ┌─────┐\n│ OK  │ │Error│\n│ Log │ │Retry│\n└─────┘ └─────┘\n",[36,12415,12413],{"__ignoreMap":38},[24,12417,12419],{"id":12418},"webhook-trigger","Webhook Trigger",[29,12421,12423],{"className":3803,"code":12422,"language":3805,"meta":38,"style":38},"{\n  \"path\": \"weighing-complete\",\n  \"httpMethod\": \"POST\",\n  \"responseMode\": \"lastNode\",\n  \"authentication\": \"headerAuth\"\n}\n",[36,12424,12425,12429,12441,12453,12465,12474],{"__ignoreMap":38},[270,12426,12427],{"class":272,"line":273},[270,12428,3812],{"class":1918},[270,12430,12431,12434,12436,12439],{"class":272,"line":279},[270,12432,12433],{"class":2053},"  \"path\"",[270,12435,1927],{"class":1918},[270,12437,12438],{"class":1930},"\"weighing-complete\"",[270,12440,3825],{"class":1918},[270,12442,12443,12446,12448,12451],{"class":272,"line":285},[270,12444,12445],{"class":2053},"  \"httpMethod\"",[270,12447,1927],{"class":1918},[270,12449,12450],{"class":1930},"\"POST\"",[270,12452,3825],{"class":1918},[270,12454,12455,12458,12460,12463],{"class":272,"line":291},[270,12456,12457],{"class":2053},"  \"responseMode\"",[270,12459,1927],{"class":1918},[270,12461,12462],{"class":1930},"\"lastNode\"",[270,12464,3825],{"class":1918},[270,12466,12467,12469,12471],{"class":272,"line":297},[270,12468,12223],{"class":2053},[270,12470,1927],{"class":1918},[270,12472,12473],{"class":1930},"\"headerAuth\"\n",[270,12475,12476],{"class":272,"line":303},[270,12477,2129],{"class":1918},[16,12479,12480],{},[93,12481,12482],{},"Example webhook call from HMI:",[29,12484,12486],{"className":1993,"code":12485,"language":1995,"meta":38,"style":38},"curl -X POST http://n8n.factory.local:5678/webhook/weighing-complete \\\n  -H \"Authorization: Bearer abc123xyz\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"batch_id\": \"MILK-2025-001\",\n    \"tank_id\": 1,\n    \"gross_weight\": 4850.5,\n    \"tare_weight\": 350.0,\n    \"net_weight\": 4500.5,\n    \"timestamp\": \"2025-12-29T14:30:00Z\"\n  }'\n",[36,12487,12488,12504,12514,12523,12531,12536,12541,12546,12551,12556,12561],{"__ignoreMap":38},[270,12489,12490,12493,12496,12499,12502],{"class":272,"line":273},[270,12491,12492],{"class":2008},"curl",[270,12494,12495],{"class":2053}," -X",[270,12497,12498],{"class":1930}," POST",[270,12500,12501],{"class":1930}," http://n8n.factory.local:5678/webhook/weighing-complete",[270,12503,10454],{"class":2053},[270,12505,12506,12509,12512],{"class":272,"line":279},[270,12507,12508],{"class":2053},"  -H",[270,12510,12511],{"class":1930}," \"Authorization: Bearer abc123xyz\"",[270,12513,10454],{"class":2053},[270,12515,12516,12518,12521],{"class":272,"line":285},[270,12517,12508],{"class":2053},[270,12519,12520],{"class":1930}," \"Content-Type: application/json\"",[270,12522,10454],{"class":2053},[270,12524,12525,12528],{"class":272,"line":291},[270,12526,12527],{"class":2053},"  -d",[270,12529,12530],{"class":1930}," '{\n",[270,12532,12533],{"class":272,"line":297},[270,12534,12535],{"class":1930},"    \"batch_id\": \"MILK-2025-001\",\n",[270,12537,12538],{"class":272,"line":303},[270,12539,12540],{"class":1930},"    \"tank_id\": 1,\n",[270,12542,12543],{"class":272,"line":515},[270,12544,12545],{"class":1930},"    \"gross_weight\": 4850.5,\n",[270,12547,12548],{"class":272,"line":793},[270,12549,12550],{"class":1930},"    \"tare_weight\": 350.0,\n",[270,12552,12553],{"class":272,"line":799},[270,12554,12555],{"class":1930},"    \"net_weight\": 4500.5,\n",[270,12557,12558],{"class":272,"line":805},[270,12559,12560],{"class":1930},"    \"timestamp\": \"2025-12-29T14:30:00Z\"\n",[270,12562,12563],{"class":272,"line":2120},[270,12564,12565],{"class":1930},"  }'\n",[24,12567,12569],{"id":12568},"function-node-sap-format-mapping","Function Node (SAP Format Mapping)",[29,12571,12573],{"className":2064,"code":12572,"language":2066,"meta":38,"style":38},"// Map weighing data to SAP production order format\nconst data = items[0].json\n\nreturn {\n  json: {\n    ProductionOrder: {\n      OrderNumber: data.batch_id,\n      Material: 'MILK-RAW',\n      Quantity: data.net_weight,\n      QuantityUnit: 'KG',\n      Plant: '1000',\n      WorkCenter: 'WEIGHING-01',\n      StartDate: data.timestamp,\n      EndDate: data.timestamp,\n      Status: 'COMPLETED',\n    },\n  },\n}\n",[36,12574,12575,12580,12585,12589,12593,12597,12602,12607,12612,12617,12622,12627,12632,12637,12642,12647,12652,12656],{"__ignoreMap":38},[270,12576,12577],{"class":272,"line":273},[270,12578,12579],{},"// Map weighing data to SAP production order format\n",[270,12581,12582],{"class":272,"line":279},[270,12583,12584],{},"const data = items[0].json\n",[270,12586,12587],{"class":272,"line":285},[270,12588,775],{"emptyLinePlaceholder":524},[270,12590,12591],{"class":272,"line":291},[270,12592,12020],{},[270,12594,12595],{"class":272,"line":297},[270,12596,12025],{},[270,12598,12599],{"class":272,"line":303},[270,12600,12601],{},"    ProductionOrder: {\n",[270,12603,12604],{"class":272,"line":515},[270,12605,12606],{},"      OrderNumber: data.batch_id,\n",[270,12608,12609],{"class":272,"line":793},[270,12610,12611],{},"      Material: 'MILK-RAW',\n",[270,12613,12614],{"class":272,"line":799},[270,12615,12616],{},"      Quantity: data.net_weight,\n",[270,12618,12619],{"class":272,"line":805},[270,12620,12621],{},"      QuantityUnit: 'KG',\n",[270,12623,12624],{"class":272,"line":2120},[270,12625,12626],{},"      Plant: '1000',\n",[270,12628,12629],{"class":272,"line":2126},[270,12630,12631],{},"      WorkCenter: 'WEIGHING-01',\n",[270,12633,12634],{"class":272,"line":2132},[270,12635,12636],{},"      StartDate: data.timestamp,\n",[270,12638,12639],{"class":272,"line":3375},[270,12640,12641],{},"      EndDate: data.timestamp,\n",[270,12643,12644],{"class":272,"line":3381},[270,12645,12646],{},"      Status: 'COMPLETED',\n",[270,12648,12649],{"class":272,"line":3387},[270,12650,12651],{},"    },\n",[270,12653,12654],{"class":272,"line":3393},[270,12655,2098],{},[270,12657,12658],{"class":272,"line":3399},[270,12659,2129],{},[24,12661,12663],{"id":12662},"http-request-to-sap","HTTP Request to SAP",[29,12665,12667],{"className":3803,"code":12666,"language":3805,"meta":38,"style":38},"{\n  \"method\": \"POST\",\n  \"url\": \"https://sap.factory.com/sap/opu/odata/sap/API_PRODUCTION_ORDER_2_SRV/A_ProductionOrder\",\n  \"authentication\": \"oAuth2\",\n  \"bodyContentType\": \"json\",\n  \"body\": \"={{$json.ProductionOrder}}\"\n}\n",[36,12668,12669,12673,12683,12694,12705,12717,12727],{"__ignoreMap":38},[270,12670,12671],{"class":272,"line":273},[270,12672,3812],{"class":1918},[270,12674,12675,12677,12679,12681],{"class":272,"line":279},[270,12676,12166],{"class":2053},[270,12678,1927],{"class":1918},[270,12680,12450],{"class":1930},[270,12682,3825],{"class":1918},[270,12684,12685,12687,12689,12692],{"class":272,"line":285},[270,12686,12178],{"class":2053},[270,12688,1927],{"class":1918},[270,12690,12691],{"class":1930},"\"https://sap.factory.com/sap/opu/odata/sap/API_PRODUCTION_ORDER_2_SRV/A_ProductionOrder\"",[270,12693,3825],{"class":1918},[270,12695,12696,12698,12700,12703],{"class":272,"line":291},[270,12697,12223],{"class":2053},[270,12699,1927],{"class":1918},[270,12701,12702],{"class":1930},"\"oAuth2\"",[270,12704,3825],{"class":1918},[270,12706,12707,12710,12712,12715],{"class":272,"line":297},[270,12708,12709],{"class":2053},"  \"bodyContentType\"",[270,12711,1927],{"class":1918},[270,12713,12714],{"class":1930},"\"json\"",[270,12716,3825],{"class":1918},[270,12718,12719,12722,12724],{"class":272,"line":303},[270,12720,12721],{"class":2053},"  \"body\"",[270,12723,1927],{"class":1918},[270,12725,12726],{"class":1930},"\"={{$json.ProductionOrder}}\"\n",[270,12728,12729],{"class":272,"line":515},[270,12730,2129],{"class":1918},[11,12732,12734],{"id":12733},"error-handling-and-retry-logic","Error Handling and Retry Logic",[24,12736,12738],{"id":12737},"retry-on-failure","Retry on Failure",[29,12740,12742],{"className":2064,"code":12741,"language":2066,"meta":38,"style":38},"// Error Handler Node\nconst MAX_RETRIES = 3\nconst currentRetry = $executionId.split('-').length - 1\n\nif (currentRetry \u003C MAX_RETRIES) {\n  // Exponential backoff\n  const waitTime = Math.pow(2, currentRetry) * 1000 // 1s, 2s, 4s\n\n  return {\n    json: {\n      retry: true,\n      wait_ms: waitTime,\n      attempt: currentRetry + 1,\n    },\n  }\n} else {\n  // Max retries exceeded, send alert\n  return {\n    json: {\n      retry: false,\n      error: 'Max retries exceeded',\n      notify_admin: true,\n    },\n  }\n}\n",[36,12743,12744,12749,12754,12759,12763,12768,12773,12778,12782,12787,12792,12797,12802,12807,12811,12815,12820,12825,12829,12833,12838,12843,12848,12852,12856],{"__ignoreMap":38},[270,12745,12746],{"class":272,"line":273},[270,12747,12748],{},"// Error Handler Node\n",[270,12750,12751],{"class":272,"line":279},[270,12752,12753],{},"const MAX_RETRIES = 3\n",[270,12755,12756],{"class":272,"line":285},[270,12757,12758],{},"const currentRetry = $executionId.split('-').length - 1\n",[270,12760,12761],{"class":272,"line":291},[270,12762,775],{"emptyLinePlaceholder":524},[270,12764,12765],{"class":272,"line":297},[270,12766,12767],{},"if (currentRetry \u003C MAX_RETRIES) {\n",[270,12769,12770],{"class":272,"line":303},[270,12771,12772],{},"  // Exponential backoff\n",[270,12774,12775],{"class":272,"line":515},[270,12776,12777],{},"  const waitTime = Math.pow(2, currentRetry) * 1000 // 1s, 2s, 4s\n",[270,12779,12780],{"class":272,"line":793},[270,12781,775],{"emptyLinePlaceholder":524},[270,12783,12784],{"class":272,"line":799},[270,12785,12786],{},"  return {\n",[270,12788,12789],{"class":272,"line":805},[270,12790,12791],{},"    json: {\n",[270,12793,12794],{"class":272,"line":2120},[270,12795,12796],{},"      retry: true,\n",[270,12798,12799],{"class":272,"line":2126},[270,12800,12801],{},"      wait_ms: waitTime,\n",[270,12803,12804],{"class":272,"line":2132},[270,12805,12806],{},"      attempt: currentRetry + 1,\n",[270,12808,12809],{"class":272,"line":3375},[270,12810,12651],{},[270,12812,12813],{"class":272,"line":3381},[270,12814,6564],{},[270,12816,12817],{"class":272,"line":3387},[270,12818,12819],{},"} else {\n",[270,12821,12822],{"class":272,"line":3393},[270,12823,12824],{},"  // Max retries exceeded, send alert\n",[270,12826,12827],{"class":272,"line":3399},[270,12828,12786],{},[270,12830,12831],{"class":272,"line":3405},[270,12832,12791],{},[270,12834,12835],{"class":272,"line":3411},[270,12836,12837],{},"      retry: false,\n",[270,12839,12840],{"class":272,"line":3417},[270,12841,12842],{},"      error: 'Max retries exceeded',\n",[270,12844,12845],{"class":272,"line":3423},[270,12846,12847],{},"      notify_admin: true,\n",[270,12849,12850],{"class":272,"line":3429},[270,12851,12651],{},[270,12853,12854],{"class":272,"line":3434},[270,12855,6564],{},[270,12857,12858],{"class":272,"line":3440},[270,12859,2129],{},[11,12861,12863],{"id":12862},"performance-and-scalability","Performance and Scalability",[24,12865,12867],{"id":12866},"n8n-resource-usage","n8n Resource Usage",[636,12869,12870,12879],{},[639,12871,12872],{},[642,12873,12874,12877],{},[645,12875,12876],{},"Metric",[645,12878,650],{},[655,12880,12881,12891,12901,12911],{},[642,12882,12883,12888],{},[660,12884,12885],{},[93,12886,12887],{},"CPU",[660,12889,12890],{},"0.5-1 core (idle)",[642,12892,12893,12898],{},[660,12894,12895],{},[93,12896,12897],{},"RAM",[660,12899,12900],{},"512 MB (idle), 2 GB (active)",[642,12902,12903,12908],{},[660,12904,12905],{},[93,12906,12907],{},"Storage",[660,12909,12910],{},"~100 MB + workflow data",[642,12912,12913,12918],{},[660,12914,12915],{},[93,12916,12917],{},"Throughput",[660,12919,12920],{},"~100 workflows/second",[24,12922,12924],{"id":12923},"scaling-for-large-facilities","Scaling for Large Facilities",[16,12926,12927],{},[93,12928,12929],{},"For 100+ sensors:",[176,12931,12932,12938,12944],{},[43,12933,12934,12937],{},[93,12935,12936],{},"Queue-based processing"," (MQTT → Redis Queue → n8n)",[43,12939,12940,12943],{},[93,12941,12942],{},"Multiple n8n instances"," (Docker Swarm/Kubernetes)",[43,12945,12946,12949],{},[93,12947,12948],{},"Database for workflow results"," (PostgreSQL)",[11,12951,444],{"id":443},[16,12953,12954,12956,12957,12960],{},[93,12955,11423],{}," enables rapid automation of complex data flows in industrial facilities ",[93,12958,12959],{},"without code",". Especially powerful for:",[16,12962,5091,12963,12966,5098,12968,12970,12971,5098,12973,12976,12977,5098,12979],{},[93,12964,12965],{},"MQTT to Email/Slack alerts",[2353,12967],{},[93,12969,5107],{}," (Excel, PDF)",[2353,12972],{},[93,12974,12975],{},"ERP system integration"," (SAP, Odoo)",[2353,12978],{},[93,12980,12981],{},"Multi-system workflows",[16,12983,1718,12984,467,12986,12988,12989,12992],{},[463,12985,1360],{"href":1613},[463,12987,2840],{"href":1723}," devices can be easily integrated with n8n via ",[93,12990,12991],{},"Modbus → MQTT gateway"," for complete workflow automation.",[24,12994,5132],{"id":5131},[40,12996,12997,13001,13005,13009],{},[43,12998,12999],{},[463,13000,2382],{"href":2340},[43,13002,13003],{},[463,13004,2377],{"href":1758},[43,13006,13007],{},[463,13008,2983],{"href":2634},[43,13010,13011],{},[463,13012,466],{"href":1613},[477,13014,13015],{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":38,"searchDepth":279,"depth":279,"links":13017},[13018,13019,13023,13024,13028,13035,13042,13049,13052,13056],{"id":13,"depth":279,"text":14},{"id":11443,"depth":279,"text":11444,"children":13020},[13021,13022],{"id":11452,"depth":285,"text":11453},{"id":11486,"depth":285,"text":11487},{"id":3279,"depth":279,"text":3280},{"id":11588,"depth":279,"text":11589,"children":13025},[13026,13027],{"id":11592,"depth":285,"text":11593},{"id":11769,"depth":285,"text":11770},{"id":11803,"depth":279,"text":11804,"children":13029},[13030,13031,13032,13033,13034],{"id":3293,"depth":285,"text":3294},{"id":11812,"depth":285,"text":11813},{"id":11867,"depth":285,"text":11868},{"id":11977,"depth":285,"text":11978},{"id":12051,"depth":285,"text":12052},{"id":12132,"depth":279,"text":12133,"children":13036},[13037,13038,13039,13040,13041],{"id":3894,"depth":285,"text":3294},{"id":12141,"depth":285,"text":12142},{"id":12151,"depth":285,"text":12152},{"id":12258,"depth":285,"text":12259},{"id":12325,"depth":285,"text":12326},{"id":12400,"depth":279,"text":12401,"children":13043},[13044,13045,13046,13047,13048],{"id":4205,"depth":285,"text":3294},{"id":12409,"depth":285,"text":12142},{"id":12418,"depth":285,"text":12419},{"id":12568,"depth":285,"text":12569},{"id":12662,"depth":285,"text":12663},{"id":12733,"depth":279,"text":12734,"children":13050},[13051],{"id":12737,"depth":285,"text":12738},{"id":12862,"depth":279,"text":12863,"children":13053},[13054,13055],{"id":12866,"depth":285,"text":12867},{"id":12923,"depth":285,"text":12924},{"id":443,"depth":279,"text":444,"children":13057},[13058],{"id":5131,"depth":285,"text":5132},"Automating industrial data flows with n8n workflow automation: MQTT to email/Slack alerts, ERP integration, and automated reporting from ZMA and GDT devices.",{"date":3011,"author":514,"readTime":805,"tags":13061},[11423,13062,6010,7985,13063,13064,13065],"Workflow Automation","No-Code","Integration","ERP",{"title":11413,"description":13059},"en/blog/industrial-iot-automation-with-n8n","JiXemAcXrnBvc7kd1R4Xaf2O_QDclassCI9P6ehKXng",{"id":13070,"title":13071,"body":13072,"description":14975,"extension":511,"meta":14976,"navigation":524,"path":5126,"seo":14980,"stem":14981,"__hash__":14982},"en_blog/en/blog/on-premise-ai-solutions-with-ollama.md","On-Premise AI Solutions with Ollama: Factory-Internal Predictive Maintenance",{"type":8,"value":13073,"toc":14945},[13074,13076,13100,13111,13115,13120,13122,13152,13156,13259,13261,13267,13271,13275,13397,13401,13428,13432,13434,13443,13454,13458,13463,13886,13890,13958,13962,13964,13970,13974,13979,14418,14422,14503,14507,14509,14514,14528,14533,14588,14592,14795,14799,14803,14808,14871,14877,14879,14888,14908,14918,14920,14942],[11,13075,14],{"id":13},[16,13077,13078,13079,467,13082,13085,13086,8017,13088,13091,13092,13095,13096,13099],{},"In industrial facilities, ",[93,13080,13081],{},"data privacy",[93,13083,13084],{},"real-time decision making"," are critical requirements. While cloud-based AI services like ",[93,13087,3041],{},[93,13089,13090],{},"OpenAI"," offer powerful capabilities, they require sensitive production data to leave the facility. ",[93,13093,13094],{},"Ollama"," addresses this issue by enabling ",[93,13097,13098],{},"local Large Language Model (LLM)"," deployment.",[16,13101,13102,13103,467,13105,13107,13108,472],{},"In this article, we examine how to implement AI-powered predictive maintenance applications using Ollama with our ",[463,13104,466],{"href":1613},[463,13106,471],{"href":1723}," devices, ",[93,13109,13110],{},"without any cloud connection",[11,13112,13114],{"id":13113},"what-is-ollama","What is Ollama?",[16,13116,13117,13119],{},[93,13118,13094],{}," is an open-source application that enables local deployment of large language models like Llama, Mistral, Phi.",[24,13121,11453],{"id":11452},[16,13123,5091,13124,13127,13128,5098,13130,13133,13134,5098,13136,13139,13140,5098,13142,13145,13146,5098,13148,13151],{},[93,13125,13126],{},"Fully Local:"," All data stays within facility",[2353,13129],{},[93,13131,13132],{},"No Internet Required:"," Complete offline operation",[2353,13135],{},[93,13137,13138],{},"Open Source Models:"," Llama 3, Mistral 7B, Phi-3",[2353,13141],{},[93,13143,13144],{},"Easy API:"," Compatible with OpenAI API",[2353,13147],{},[93,13149,13150],{},"Low Cost:"," No per-token API fees",[24,13153,13155],{"id":13154},"cloud-ai-vs-ollama-comparison","Cloud AI vs Ollama Comparison",[636,13157,13158,13172],{},[639,13159,13160],{},[642,13161,13162,13164,13166,13169],{},[645,13163,647],{},[645,13165,3041],{},[645,13167,13168],{},"OpenAI GPT-4",[645,13170,13171],{},"Ollama (Local)",[655,13173,13174,13186,13201,13213,13227,13243],{},[642,13175,13176,13180,13182,13184],{},[660,13177,13178],{},[93,13179,3207],{},[660,13181,3213],{},[660,13183,3213],{},[660,13185,3216],{},[642,13187,13188,13193,13196,13198],{},[660,13189,13190],{},[93,13191,13192],{},"Internet Dependency",[660,13194,13195],{},"Required",[660,13197,13195],{},[660,13199,13200],{},"Not required",[642,13202,13203,13207,13209,13211],{},[660,13204,13205],{},[93,13206,626],{},[660,13208,3225],{},[660,13210,3228],{},[660,13212,3231],{},[642,13214,13215,13219,13222,13225],{},[660,13216,13217],{},[93,13218,2217],{},[660,13220,13221],{},"$0.00025-0.01/1K token",[660,13223,13224],{},"$0.01-0.06/1K token",[660,13226,3245],{},[642,13228,13229,13234,13237,13240],{},[660,13230,13231],{},[93,13232,13233],{},"Customization",[660,13235,13236],{},"Limited",[660,13238,13239],{},"No",[660,13241,13242],{},"Full control",[642,13244,13245,13250,13253,13256],{},[660,13246,13247],{},[93,13248,13249],{},"Model Size",[660,13251,13252],{},"Large (100B+)",[660,13254,13255],{},"Very large (1.7T)",[660,13257,13258],{},"Small-Medium (7B-70B)",[11,13260,3280],{"id":3279},[29,13262,13265],{"className":13263,"code":13264,"language":34},[32],"┌──────────────────────────────────────────────────┐\n│              Factory (Fully Offline)             │\n│                                                  │\n│  ┌─────────┐    Modbus TCP    ┌──────────────┐  │\n│  │ ZMA-4   │◄─────────────────►│              │  │\n│  │ Devices │                   │  Linux PC    │  │\n│  └─────────┘                   │  (AI Server) │  │\n│                                │              │  │\n│  ┌─────────┐    Modbus TCP    │ - Ollama     │  │\n│  │ GDT     │◄─────────────────►│ - Python     │  │\n│  │ Trans.  │                   │ - PostgreSQL │  │\n│  └─────────┘                   │              │  │\n│                                │ Models:      │  │\n│                                │ • Llama 3.2  │  │\n│                                │ • Mistral 7B │  │\n│                                │ • Phi-3      │  │\n│                                └──────────────┘  │\n│                                                  │\n└──────────────────────────────────────────────────┘\n",[36,13266,13264],{"__ignoreMap":38},[11,13268,13270],{"id":13269},"ollama-installation-and-setup","Ollama Installation and Setup",[24,13272,13274],{"id":13273},"_1-server-installation-ubuntu-2204","1. Server Installation (Ubuntu 22.04)",[29,13276,13278],{"className":1993,"code":13277,"language":1995,"meta":38,"style":38},"# Install Ollama\ncurl -fsSL https://ollama.com/install.sh | sh\n\n# Start Ollama service\nsudo systemctl start ollama\nsudo systemctl enable ollama\n\n# Download models\nollama pull llama3.2:3b      # 3B parameter model (~2GB)\nollama pull mistral:7b       # 7B parameter model (~4.1GB)\nollama pull phi3:medium      # 14B parameter model (~7.9GB)\n\n# Verify installation\nollama list\n",[36,13279,13280,13285,13301,13305,13310,13323,13334,13338,13343,13357,13369,13381,13385,13390],{"__ignoreMap":38},[270,13281,13282],{"class":272,"line":273},[270,13283,13284],{"class":2002},"# Install Ollama\n",[270,13286,13287,13289,13292,13295,13298],{"class":272,"line":279},[270,13288,12492],{"class":2008},[270,13290,13291],{"class":2053}," -fsSL",[270,13293,13294],{"class":1930}," https://ollama.com/install.sh",[270,13296,13297],{"class":1962}," |",[270,13299,13300],{"class":2008}," sh\n",[270,13302,13303],{"class":272,"line":285},[270,13304,775],{"emptyLinePlaceholder":524},[270,13306,13307],{"class":272,"line":291},[270,13308,13309],{"class":2002},"# Start Ollama service\n",[270,13311,13312,13314,13317,13320],{"class":272,"line":297},[270,13313,2009],{"class":2008},[270,13315,13316],{"class":1930}," systemctl",[270,13318,13319],{"class":1930}," start",[270,13321,13322],{"class":1930}," ollama\n",[270,13324,13325,13327,13329,13332],{"class":272,"line":303},[270,13326,2009],{"class":2008},[270,13328,13316],{"class":1930},[270,13330,13331],{"class":1930}," enable",[270,13333,13322],{"class":1930},[270,13335,13336],{"class":272,"line":515},[270,13337,775],{"emptyLinePlaceholder":524},[270,13339,13340],{"class":272,"line":793},[270,13341,13342],{"class":2002},"# Download models\n",[270,13344,13345,13348,13351,13354],{"class":272,"line":799},[270,13346,13347],{"class":2008},"ollama",[270,13349,13350],{"class":1930}," pull",[270,13352,13353],{"class":1930}," llama3.2:3b",[270,13355,13356],{"class":2002},"      # 3B parameter model (~2GB)\n",[270,13358,13359,13361,13363,13366],{"class":272,"line":805},[270,13360,13347],{"class":2008},[270,13362,13350],{"class":1930},[270,13364,13365],{"class":1930}," mistral:7b",[270,13367,13368],{"class":2002},"       # 7B parameter model (~4.1GB)\n",[270,13370,13371,13373,13375,13378],{"class":272,"line":2120},[270,13372,13347],{"class":2008},[270,13374,13350],{"class":1930},[270,13376,13377],{"class":1930}," phi3:medium",[270,13379,13380],{"class":2002},"      # 14B parameter model (~7.9GB)\n",[270,13382,13383],{"class":272,"line":2126},[270,13384,775],{"emptyLinePlaceholder":524},[270,13386,13387],{"class":272,"line":2132},[270,13388,13389],{"class":2002},"# Verify installation\n",[270,13391,13392,13394],{"class":272,"line":3375},[270,13393,13347],{"class":2008},[270,13395,13396],{"class":1930}," list\n",[24,13398,13400],{"id":13399},"_2-python-integration","2. Python Integration",[29,13402,13404],{"className":1993,"code":13403,"language":1995,"meta":38,"style":38},"pip install ollama requests pymodbus psycopg2-binary pandas\n",[36,13405,13406],{"__ignoreMap":38},[270,13407,13408,13411,13413,13416,13419,13422,13425],{"class":272,"line":273},[270,13409,13410],{"class":2008},"pip",[270,13412,2015],{"class":1930},[270,13414,13415],{"class":1930}," ollama",[270,13417,13418],{"class":1930}," requests",[270,13420,13421],{"class":1930}," pymodbus",[270,13423,13424],{"class":1930}," psycopg2-binary",[270,13426,13427],{"class":1930}," pandas\n",[11,13429,13431],{"id":13430},"application-1-anomaly-detection-from-loadcell-data","Application 1: Anomaly Detection from Loadcell Data",[24,13433,3294],{"id":3293},[16,13435,13436,13438,13439,13442],{},[463,13437,471],{"href":1723}," reads weight from 4 loadcells on a tank. ",[93,13440,13441],{},"Imbalanced load"," (one loadcell reading much higher/lower) may indicate:",[40,13444,13445,13448,13451],{},[43,13446,13447],{},"Tank tilt",[43,13449,13450],{},"Loadcell failure",[43,13452,13453],{},"Foundation problem",[24,13455,13457],{"id":13456},"ai-powered-detection","AI-Powered Detection",[16,13459,13460],{},[93,13461,13462],{},"anomaly_detector.py",[29,13464,13466],{"className":751,"code":13465,"language":753,"meta":38,"style":38},"#!/usr/bin/env python3\n\nimport ollama\nimport json\nfrom pymodbus.client.sync import ModbusTcpClient\n\nclass LoadcellAnomalyDetector:\n    def __init__(self):\n        self.gdt_client = ModbusTcpClient('192.168.1.100', port=502)\n        self.gdt_client.connect()\n\n        # Use lightweight model (3B)\n        self.model = \"llama3.2:3b\"\n\n    def read_loadcells(self):\n        \"\"\"Read 4 loadcell values from GDT\"\"\"\n        result = self.gdt_client.read_holding_registers(10, 8, unit=1)\n\n        if not result.isError():\n            lc1 = self._to_float(result.registers[0:2])\n            lc2 = self._to_float(result.registers[2:4])\n            lc3 = self._to_float(result.registers[4:6])\n            lc4 = self._to_float(result.registers[6:8])\n\n            return {\n                \"lc1\": round(lc1, 3),\n                \"lc2\": round(lc2, 3),\n                \"lc3\": round(lc3, 3),\n                \"lc4\": round(lc4, 3),\n                \"total\": round(lc1 + lc2 + lc3 + lc4, 3)\n            }\n        return None\n\n    def analyze_with_ai(self, data):\n        \"\"\"Analyze loadcell values with Ollama\"\"\"\n        prompt = f\"\"\"\nYou are an industrial automation expert. Analyze the following loadcell readings:\n\nLoadcell 1 (Front-Left):  {data['lc1']} mV/V\nLoadcell 2 (Front-Right): {data['lc2']} mV/V\nLoadcell 3 (Rear-Left):   {data['lc3']} mV/V\nLoadcell 4 (Rear-Right):  {data['lc4']} mV/V\nTotal Weight: {data['total']} mV/V\n\nNormal state: All 4 loadcells should read similar values (±5% tolerance).\n\nTask: Detect any anomalies and provide:\n1. Is there an anomaly? (Yes/No)\n2. If yes, which loadcell?\n3. Probable cause\n4. Recommended action\n\nRespond in JSON format.\n\"\"\"\n\n        response = ollama.generate(\n            model=self.model,\n            prompt=prompt,\n            format='json'  # Force JSON output\n        )\n\n        result = json.loads(response['response'])\n        return result\n\n    def run(self):\n        \"\"\"Main monitoring loop\"\"\"\n        print(f\"🤖 AI Anomaly Detector started (Model: {self.model})\")\n\n        while True:\n            data = self.read_loadcells()\n\n            if data:\n                print(f\"\\n📊 Loadcells: {data}\")\n\n                # AI analysis\n                analysis = self.analyze_with_ai(data)\n\n                if analysis.get('anomaly') == 'Yes':\n                    print(f\"⚠️  ANOMALY DETECTED!\")\n                    print(f\"   Problem: {analysis.get('problem')}\")\n                    print(f\"   Cause: {analysis.get('probable_cause')}\")\n                    print(f\"   Action: {analysis.get('recommended_action')}\")\n                else:\n                    print(\"✓ Normal operation\")\n\n            time.sleep(10)  # Check every 10 seconds\n\nif __name__ == \"__main__\":\n    detector = LoadcellAnomalyDetector()\n    detector.run()\n",[36,13467,13468,13472,13476,13481,13485,13489,13493,13498,13502,13507,13512,13516,13521,13526,13530,13535,13540,13545,13549,13553,13558,13563,13568,13573,13577,13581,13586,13591,13596,13601,13606,13610,13614,13618,13623,13628,13633,13638,13642,13647,13652,13657,13662,13667,13671,13676,13680,13685,13690,13695,13700,13705,13709,13714,13718,13722,13727,13732,13737,13742,13746,13750,13755,13760,13764,13768,13773,13778,13782,13787,13792,13796,13801,13806,13810,13815,13820,13824,13829,13834,13839,13844,13849,13854,13859,13863,13868,13872,13876,13881],{"__ignoreMap":38},[270,13469,13470],{"class":272,"line":273},[270,13471,7066],{},[270,13473,13474],{"class":272,"line":279},[270,13475,775],{"emptyLinePlaceholder":524},[270,13477,13478],{"class":272,"line":285},[270,13479,13480],{},"import ollama\n",[270,13482,13483],{"class":272,"line":291},[270,13484,3319],{},[270,13486,13487],{"class":272,"line":297},[270,13488,7085],{},[270,13490,13491],{"class":272,"line":303},[270,13492,775],{"emptyLinePlaceholder":524},[270,13494,13495],{"class":272,"line":515},[270,13496,13497],{},"class LoadcellAnomalyDetector:\n",[270,13499,13500],{"class":272,"line":793},[270,13501,7109],{},[270,13503,13504],{"class":272,"line":799},[270,13505,13506],{},"        self.gdt_client = ModbusTcpClient('192.168.1.100', port=502)\n",[270,13508,13509],{"class":272,"line":805},[270,13510,13511],{},"        self.gdt_client.connect()\n",[270,13513,13514],{"class":272,"line":2120},[270,13515,775],{"emptyLinePlaceholder":524},[270,13517,13518],{"class":272,"line":2126},[270,13519,13520],{},"        # Use lightweight model (3B)\n",[270,13522,13523],{"class":272,"line":2132},[270,13524,13525],{},"        self.model = \"llama3.2:3b\"\n",[270,13527,13528],{"class":272,"line":3375},[270,13529,775],{"emptyLinePlaceholder":524},[270,13531,13532],{"class":272,"line":3381},[270,13533,13534],{},"    def read_loadcells(self):\n",[270,13536,13537],{"class":272,"line":3387},[270,13538,13539],{},"        \"\"\"Read 4 loadcell values from GDT\"\"\"\n",[270,13541,13542],{"class":272,"line":3393},[270,13543,13544],{},"        result = self.gdt_client.read_holding_registers(10, 8, unit=1)\n",[270,13546,13547],{"class":272,"line":3399},[270,13548,775],{"emptyLinePlaceholder":524},[270,13550,13551],{"class":272,"line":3405},[270,13552,7306],{},[270,13554,13555],{"class":272,"line":3411},[270,13556,13557],{},"            lc1 = self._to_float(result.registers[0:2])\n",[270,13559,13560],{"class":272,"line":3417},[270,13561,13562],{},"            lc2 = self._to_float(result.registers[2:4])\n",[270,13564,13565],{"class":272,"line":3423},[270,13566,13567],{},"            lc3 = self._to_float(result.registers[4:6])\n",[270,13569,13570],{"class":272,"line":3429},[270,13571,13572],{},"            lc4 = self._to_float(result.registers[6:8])\n",[270,13574,13575],{"class":272,"line":3434},[270,13576,775],{"emptyLinePlaceholder":524},[270,13578,13579],{"class":272,"line":3440},[270,13580,7330],{},[270,13582,13583],{"class":272,"line":3446},[270,13584,13585],{},"                \"lc1\": round(lc1, 3),\n",[270,13587,13588],{"class":272,"line":3452},[270,13589,13590],{},"                \"lc2\": round(lc2, 3),\n",[270,13592,13593],{"class":272,"line":3457},[270,13594,13595],{},"                \"lc3\": round(lc3, 3),\n",[270,13597,13598],{"class":272,"line":3463},[270,13599,13600],{},"                \"lc4\": round(lc4, 3),\n",[270,13602,13603],{"class":272,"line":3469},[270,13604,13605],{},"                \"total\": round(lc1 + lc2 + lc3 + lc4, 3)\n",[270,13607,13608],{"class":272,"line":3475},[270,13609,4592],{},[270,13611,13612],{"class":272,"line":3480},[270,13613,7373],{},[270,13615,13616],{"class":272,"line":3486},[270,13617,775],{"emptyLinePlaceholder":524},[270,13619,13620],{"class":272,"line":3492},[270,13621,13622],{},"    def analyze_with_ai(self, data):\n",[270,13624,13625],{"class":272,"line":3497},[270,13626,13627],{},"        \"\"\"Analyze loadcell values with Ollama\"\"\"\n",[270,13629,13630],{"class":272,"line":3503},[270,13631,13632],{},"        prompt = f\"\"\"\n",[270,13634,13635],{"class":272,"line":3509},[270,13636,13637],{},"You are an industrial automation expert. Analyze the following loadcell readings:\n",[270,13639,13640],{"class":272,"line":3515},[270,13641,775],{"emptyLinePlaceholder":524},[270,13643,13644],{"class":272,"line":3521},[270,13645,13646],{},"Loadcell 1 (Front-Left):  {data['lc1']} mV/V\n",[270,13648,13649],{"class":272,"line":3527},[270,13650,13651],{},"Loadcell 2 (Front-Right): {data['lc2']} mV/V\n",[270,13653,13654],{"class":272,"line":3532},[270,13655,13656],{},"Loadcell 3 (Rear-Left):   {data['lc3']} mV/V\n",[270,13658,13659],{"class":272,"line":3538},[270,13660,13661],{},"Loadcell 4 (Rear-Right):  {data['lc4']} mV/V\n",[270,13663,13664],{"class":272,"line":3544},[270,13665,13666],{},"Total Weight: {data['total']} mV/V\n",[270,13668,13669],{"class":272,"line":3550},[270,13670,775],{"emptyLinePlaceholder":524},[270,13672,13673],{"class":272,"line":3556},[270,13674,13675],{},"Normal state: All 4 loadcells should read similar values (±5% tolerance).\n",[270,13677,13678],{"class":272,"line":3562},[270,13679,775],{"emptyLinePlaceholder":524},[270,13681,13682],{"class":272,"line":3568},[270,13683,13684],{},"Task: Detect any anomalies and provide:\n",[270,13686,13687],{"class":272,"line":3574},[270,13688,13689],{},"1. Is there an anomaly? (Yes/No)\n",[270,13691,13692],{"class":272,"line":3580},[270,13693,13694],{},"2. If yes, which loadcell?\n",[270,13696,13697],{"class":272,"line":3586},[270,13698,13699],{},"3. Probable cause\n",[270,13701,13702],{"class":272,"line":3592},[270,13703,13704],{},"4. Recommended action\n",[270,13706,13707],{"class":272,"line":3597},[270,13708,775],{"emptyLinePlaceholder":524},[270,13710,13711],{"class":272,"line":3603},[270,13712,13713],{},"Respond in JSON format.\n",[270,13715,13716],{"class":272,"line":3609},[270,13717,3589],{},[270,13719,13720],{"class":272,"line":3615},[270,13721,775],{"emptyLinePlaceholder":524},[270,13723,13724],{"class":272,"line":3621},[270,13725,13726],{},"        response = ollama.generate(\n",[270,13728,13729],{"class":272,"line":3627},[270,13730,13731],{},"            model=self.model,\n",[270,13733,13734],{"class":272,"line":3633},[270,13735,13736],{},"            prompt=prompt,\n",[270,13738,13739],{"class":272,"line":3639},[270,13740,13741],{},"            format='json'  # Force JSON output\n",[270,13743,13744],{"class":272,"line":3645},[270,13745,3766],{},[270,13747,13748],{"class":272,"line":3651},[270,13749,775],{"emptyLinePlaceholder":524},[270,13751,13752],{"class":272,"line":3657},[270,13753,13754],{},"        result = json.loads(response['response'])\n",[270,13756,13757],{"class":272,"line":3663},[270,13758,13759],{},"        return result\n",[270,13761,13762],{"class":272,"line":3669},[270,13763,775],{"emptyLinePlaceholder":524},[270,13765,13766],{"class":272,"line":3675},[270,13767,7532],{},[270,13769,13770],{"class":272,"line":3681},[270,13771,13772],{},"        \"\"\"Main monitoring loop\"\"\"\n",[270,13774,13775],{"class":272,"line":3687},[270,13776,13777],{},"        print(f\"🤖 AI Anomaly Detector started (Model: {self.model})\")\n",[270,13779,13780],{"class":272,"line":3693},[270,13781,775],{"emptyLinePlaceholder":524},[270,13783,13784],{"class":272,"line":3698},[270,13785,13786],{},"        while True:\n",[270,13788,13789],{"class":272,"line":3704},[270,13790,13791],{},"            data = self.read_loadcells()\n",[270,13793,13794],{"class":272,"line":3710},[270,13795,775],{"emptyLinePlaceholder":524},[270,13797,13798],{"class":272,"line":3716},[270,13799,13800],{},"            if data:\n",[270,13802,13803],{"class":272,"line":3721},[270,13804,13805],{},"                print(f\"\\n📊 Loadcells: {data}\")\n",[270,13807,13808],{"class":272,"line":3727},[270,13809,775],{"emptyLinePlaceholder":524},[270,13811,13812],{"class":272,"line":3733},[270,13813,13814],{},"                # AI analysis\n",[270,13816,13817],{"class":272,"line":3739},[270,13818,13819],{},"                analysis = self.analyze_with_ai(data)\n",[270,13821,13822],{"class":272,"line":3745},[270,13823,775],{"emptyLinePlaceholder":524},[270,13825,13826],{"class":272,"line":3751},[270,13827,13828],{},"                if analysis.get('anomaly') == 'Yes':\n",[270,13830,13831],{"class":272,"line":3757},[270,13832,13833],{},"                    print(f\"⚠️  ANOMALY DETECTED!\")\n",[270,13835,13836],{"class":272,"line":3763},[270,13837,13838],{},"                    print(f\"   Problem: {analysis.get('problem')}\")\n",[270,13840,13841],{"class":272,"line":3769},[270,13842,13843],{},"                    print(f\"   Cause: {analysis.get('probable_cause')}\")\n",[270,13845,13846],{"class":272,"line":3774},[270,13847,13848],{},"                    print(f\"   Action: {analysis.get('recommended_action')}\")\n",[270,13850,13851],{"class":272,"line":3780},[270,13852,13853],{},"                else:\n",[270,13855,13856],{"class":272,"line":3786},[270,13857,13858],{},"                    print(\"✓ Normal operation\")\n",[270,13860,13861],{"class":272,"line":3792},[270,13862,775],{"emptyLinePlaceholder":524},[270,13864,13865],{"class":272,"line":7470},[270,13866,13867],{},"            time.sleep(10)  # Check every 10 seconds\n",[270,13869,13870],{"class":272,"line":7476},[270,13871,775],{"emptyLinePlaceholder":524},[270,13873,13874],{"class":272,"line":7482},[270,13875,7664],{},[270,13877,13878],{"class":272,"line":7488},[270,13879,13880],{},"    detector = LoadcellAnomalyDetector()\n",[270,13882,13883],{"class":272,"line":7494},[270,13884,13885],{},"    detector.run()\n",[16,13887,13888],{},[93,13889,3800],{},[29,13891,13893],{"className":3803,"code":13892,"language":3805,"meta":38,"style":38},"{\n  \"anomaly\": \"Yes\",\n  \"problem\": \"Loadcell 3 reading is 15% lower than others\",\n  \"probable_cause\": \"Possible loadcell drift or loose connection\",\n  \"recommended_action\": \"Check Loadcell 3 wiring and recalibrate if necessary\",\n  \"severity\": \"Medium\"\n}\n",[36,13894,13895,13899,13911,13923,13934,13945,13954],{"__ignoreMap":38},[270,13896,13897],{"class":272,"line":273},[270,13898,3812],{"class":1918},[270,13900,13901,13904,13906,13909],{"class":272,"line":279},[270,13902,13903],{"class":2053},"  \"anomaly\"",[270,13905,1927],{"class":1918},[270,13907,13908],{"class":1930},"\"Yes\"",[270,13910,3825],{"class":1918},[270,13912,13913,13916,13918,13921],{"class":272,"line":285},[270,13914,13915],{"class":2053},"  \"problem\"",[270,13917,1927],{"class":1918},[270,13919,13920],{"class":1930},"\"Loadcell 3 reading is 15% lower than others\"",[270,13922,3825],{"class":1918},[270,13924,13925,13927,13929,13932],{"class":272,"line":291},[270,13926,3854],{"class":2053},[270,13928,1927],{"class":1918},[270,13930,13931],{"class":1930},"\"Possible loadcell drift or loose connection\"",[270,13933,3825],{"class":1918},[270,13935,13936,13938,13940,13943],{"class":272,"line":297},[270,13937,3866],{"class":2053},[270,13939,1927],{"class":1918},[270,13941,13942],{"class":1930},"\"Check Loadcell 3 wiring and recalibrate if necessary\"",[270,13944,3825],{"class":1918},[270,13946,13947,13949,13951],{"class":272,"line":303},[270,13948,3842],{"class":2053},[270,13950,1927],{"class":1918},[270,13952,13953],{"class":1930},"\"Medium\"\n",[270,13955,13956],{"class":272,"line":515},[270,13957,2129],{"class":1918},[11,13959,13961],{"id":13960},"application-2-predictive-maintenance-from-vibration-data","Application 2: Predictive Maintenance from Vibration Data",[24,13963,3294],{"id":3894},[16,13965,13966,13969],{},[463,13967,13968],{"href":1613},"ZMA-4"," collects vibration data from motor via accelerometer (4-20mA). Predict motor failure by analyzing data with AI.",[24,13971,13973],{"id":13972},"feature-extraction-ai-analysis","Feature Extraction + AI Analysis",[16,13975,13976],{},[93,13977,13978],{},"vibration_monitor.py",[29,13980,13982],{"className":751,"code":13981,"language":753,"meta":38,"style":38},"import numpy as np\nimport pandas as pd\nfrom scipy import signal\nfrom pymodbus.client.sync import ModbusTcpClient\nimport ollama\n\nclass VibrationAnalyzer:\n    def __init__(self):\n        self.zma_client = ModbusTcpClient('192.168.1.50', port=502)\n        self.zma_client.connect()\n        self.model = \"mistral:7b\"\n\n    def read_vibration_data(self, samples=1000):\n        \"\"\"Read 1000 samples from ZMA (1kHz sampling)\"\"\"\n        data = []\n        for _ in range(samples):\n            result = self.zma_client.read_holding_registers(0, 2, unit=1)\n            value = self._to_float(result.registers)\n            data.append(value)\n            time.sleep(0.001)  # 1ms = 1kHz\n\n        return np.array(data)\n\n    def extract_features(self, vibration_data):\n        \"\"\"Extract frequency domain features\"\"\"\n        # FFT\n        fft = np.fft.fft(vibration_data)\n        freqs = np.fft.fftfreq(len(vibration_data), d=0.001)\n\n        # Peak frequencies\n        peaks, _ = signal.find_peaks(np.abs(fft), height=100)\n        peak_freqs = freqs[peaks]\n\n        # Statistical features\n        features = {\n            \"rms\": np.sqrt(np.mean(vibration_data**2)),\n            \"peak\": np.max(np.abs(vibration_data)),\n            \"crest_factor\": np.max(np.abs(vibration_data)) / np.sqrt(np.mean(vibration_data**2)),\n            \"dominant_freq\": peak_freqs[0] if len(peak_freqs) > 0 else 0,\n            \"spectral_energy\": np.sum(np.abs(fft)**2)\n        }\n\n        return features\n\n    def predict_with_ai(self, features):\n        \"\"\"Predictive maintenance analysis with AI\"\"\"\n        prompt = f\"\"\"\nYou are a mechanical engineer expert in predictive maintenance. Analyze the following vibration data from an industrial motor:\n\nRMS Vibration: {features['rms']:.3f} m/s²\nPeak Vibration: {features['peak']:.3f} m/s²\nCrest Factor: {features['crest_factor']:.2f}\nDominant Frequency: {features['dominant_freq']:.1f} Hz\nSpectral Energy: {features['spectral_energy']:.2e}\n\nReference values:\n- Normal RMS: 0.5-2.0 m/s²\n- Warning RMS: 2.0-5.0 m/s²\n- Critical RMS: >5.0 m/s²\n- Normal Crest Factor: 3-4\n- Motor rotation: 1500 RPM (25 Hz)\n\nTask: Provide predictive maintenance assessment:\n1. Motor condition (Normal/Warning/Critical)\n2. Probable fault type (if any)\n3. Estimated time to failure (days)\n4. Recommended action\n\nRespond in JSON format.\n\"\"\"\n\n        response = ollama.generate(\n            model=self.model,\n            prompt=prompt,\n            format='json'\n        )\n\n        return json.loads(response['response'])\n\nif __name__ == \"__main__\":\n    analyzer = VibrationAnalyzer()\n\n    # Read vibration data\n    vibration = analyzer.read_vibration_data(1000)\n\n    # Extract features\n    features = analyzer.extract_features(vibration)\n    print(f\"📊 Features: {features}\")\n\n    # AI prediction\n    prediction = analyzer.predict_with_ai(features)\n    print(f\"\\n🔮 AI Prediction:\")\n    print(json.dumps(prediction, indent=2))\n",[36,13983,13984,13989,13994,13999,14003,14007,14011,14016,14020,14025,14030,14035,14039,14044,14049,14054,14059,14064,14069,14074,14079,14083,14088,14092,14097,14102,14107,14112,14117,14121,14126,14131,14136,14140,14145,14150,14155,14160,14165,14170,14175,14179,14183,14188,14192,14197,14202,14206,14211,14215,14220,14225,14230,14235,14240,14244,14249,14254,14259,14264,14269,14274,14278,14283,14288,14293,14298,14302,14306,14310,14314,14318,14322,14326,14330,14335,14339,14343,14348,14352,14356,14361,14365,14370,14375,14379,14384,14389,14394,14398,14403,14408,14413],{"__ignoreMap":38},[270,13985,13986],{"class":272,"line":273},[270,13987,13988],{},"import numpy as np\n",[270,13990,13991],{"class":272,"line":279},[270,13992,13993],{},"import pandas as pd\n",[270,13995,13996],{"class":272,"line":285},[270,13997,13998],{},"from scipy import signal\n",[270,14000,14001],{"class":272,"line":291},[270,14002,7085],{},[270,14004,14005],{"class":272,"line":297},[270,14006,13480],{},[270,14008,14009],{"class":272,"line":303},[270,14010,775],{"emptyLinePlaceholder":524},[270,14012,14013],{"class":272,"line":515},[270,14014,14015],{},"class VibrationAnalyzer:\n",[270,14017,14018],{"class":272,"line":793},[270,14019,7109],{},[270,14021,14022],{"class":272,"line":799},[270,14023,14024],{},"        self.zma_client = ModbusTcpClient('192.168.1.50', port=502)\n",[270,14026,14027],{"class":272,"line":805},[270,14028,14029],{},"        self.zma_client.connect()\n",[270,14031,14032],{"class":272,"line":2120},[270,14033,14034],{},"        self.model = \"mistral:7b\"\n",[270,14036,14037],{"class":272,"line":2126},[270,14038,775],{"emptyLinePlaceholder":524},[270,14040,14041],{"class":272,"line":2132},[270,14042,14043],{},"    def read_vibration_data(self, samples=1000):\n",[270,14045,14046],{"class":272,"line":3375},[270,14047,14048],{},"        \"\"\"Read 1000 samples from ZMA (1kHz sampling)\"\"\"\n",[270,14050,14051],{"class":272,"line":3381},[270,14052,14053],{},"        data = []\n",[270,14055,14056],{"class":272,"line":3387},[270,14057,14058],{},"        for _ in range(samples):\n",[270,14060,14061],{"class":272,"line":3393},[270,14062,14063],{},"            result = self.zma_client.read_holding_registers(0, 2, unit=1)\n",[270,14065,14066],{"class":272,"line":3399},[270,14067,14068],{},"            value = self._to_float(result.registers)\n",[270,14070,14071],{"class":272,"line":3405},[270,14072,14073],{},"            data.append(value)\n",[270,14075,14076],{"class":272,"line":3411},[270,14077,14078],{},"            time.sleep(0.001)  # 1ms = 1kHz\n",[270,14080,14081],{"class":272,"line":3417},[270,14082,775],{"emptyLinePlaceholder":524},[270,14084,14085],{"class":272,"line":3423},[270,14086,14087],{},"        return np.array(data)\n",[270,14089,14090],{"class":272,"line":3429},[270,14091,775],{"emptyLinePlaceholder":524},[270,14093,14094],{"class":272,"line":3434},[270,14095,14096],{},"    def extract_features(self, vibration_data):\n",[270,14098,14099],{"class":272,"line":3440},[270,14100,14101],{},"        \"\"\"Extract frequency domain features\"\"\"\n",[270,14103,14104],{"class":272,"line":3446},[270,14105,14106],{},"        # FFT\n",[270,14108,14109],{"class":272,"line":3452},[270,14110,14111],{},"        fft = np.fft.fft(vibration_data)\n",[270,14113,14114],{"class":272,"line":3457},[270,14115,14116],{},"        freqs = np.fft.fftfreq(len(vibration_data), d=0.001)\n",[270,14118,14119],{"class":272,"line":3463},[270,14120,775],{"emptyLinePlaceholder":524},[270,14122,14123],{"class":272,"line":3469},[270,14124,14125],{},"        # Peak frequencies\n",[270,14127,14128],{"class":272,"line":3475},[270,14129,14130],{},"        peaks, _ = signal.find_peaks(np.abs(fft), height=100)\n",[270,14132,14133],{"class":272,"line":3480},[270,14134,14135],{},"        peak_freqs = freqs[peaks]\n",[270,14137,14138],{"class":272,"line":3486},[270,14139,775],{"emptyLinePlaceholder":524},[270,14141,14142],{"class":272,"line":3492},[270,14143,14144],{},"        # Statistical features\n",[270,14146,14147],{"class":272,"line":3497},[270,14148,14149],{},"        features = {\n",[270,14151,14152],{"class":272,"line":3503},[270,14153,14154],{},"            \"rms\": np.sqrt(np.mean(vibration_data**2)),\n",[270,14156,14157],{"class":272,"line":3509},[270,14158,14159],{},"            \"peak\": np.max(np.abs(vibration_data)),\n",[270,14161,14162],{"class":272,"line":3515},[270,14163,14164],{},"            \"crest_factor\": np.max(np.abs(vibration_data)) / np.sqrt(np.mean(vibration_data**2)),\n",[270,14166,14167],{"class":272,"line":3521},[270,14168,14169],{},"            \"dominant_freq\": peak_freqs[0] if len(peak_freqs) > 0 else 0,\n",[270,14171,14172],{"class":272,"line":3527},[270,14173,14174],{},"            \"spectral_energy\": np.sum(np.abs(fft)**2)\n",[270,14176,14177],{"class":272,"line":3532},[270,14178,4491],{},[270,14180,14181],{"class":272,"line":3538},[270,14182,775],{"emptyLinePlaceholder":524},[270,14184,14185],{"class":272,"line":3544},[270,14186,14187],{},"        return features\n",[270,14189,14190],{"class":272,"line":3550},[270,14191,775],{"emptyLinePlaceholder":524},[270,14193,14194],{"class":272,"line":3556},[270,14195,14196],{},"    def predict_with_ai(self, features):\n",[270,14198,14199],{"class":272,"line":3562},[270,14200,14201],{},"        \"\"\"Predictive maintenance analysis with AI\"\"\"\n",[270,14203,14204],{"class":272,"line":3568},[270,14205,13632],{},[270,14207,14208],{"class":272,"line":3574},[270,14209,14210],{},"You are a mechanical engineer expert in predictive maintenance. Analyze the following vibration data from an industrial motor:\n",[270,14212,14213],{"class":272,"line":3580},[270,14214,775],{"emptyLinePlaceholder":524},[270,14216,14217],{"class":272,"line":3586},[270,14218,14219],{},"RMS Vibration: {features['rms']:.3f} m/s²\n",[270,14221,14222],{"class":272,"line":3592},[270,14223,14224],{},"Peak Vibration: {features['peak']:.3f} m/s²\n",[270,14226,14227],{"class":272,"line":3597},[270,14228,14229],{},"Crest Factor: {features['crest_factor']:.2f}\n",[270,14231,14232],{"class":272,"line":3603},[270,14233,14234],{},"Dominant Frequency: {features['dominant_freq']:.1f} Hz\n",[270,14236,14237],{"class":272,"line":3609},[270,14238,14239],{},"Spectral Energy: {features['spectral_energy']:.2e}\n",[270,14241,14242],{"class":272,"line":3615},[270,14243,775],{"emptyLinePlaceholder":524},[270,14245,14246],{"class":272,"line":3621},[270,14247,14248],{},"Reference values:\n",[270,14250,14251],{"class":272,"line":3627},[270,14252,14253],{},"- Normal RMS: 0.5-2.0 m/s²\n",[270,14255,14256],{"class":272,"line":3633},[270,14257,14258],{},"- Warning RMS: 2.0-5.0 m/s²\n",[270,14260,14261],{"class":272,"line":3639},[270,14262,14263],{},"- Critical RMS: >5.0 m/s²\n",[270,14265,14266],{"class":272,"line":3645},[270,14267,14268],{},"- Normal Crest Factor: 3-4\n",[270,14270,14271],{"class":272,"line":3651},[270,14272,14273],{},"- Motor rotation: 1500 RPM (25 Hz)\n",[270,14275,14276],{"class":272,"line":3657},[270,14277,775],{"emptyLinePlaceholder":524},[270,14279,14280],{"class":272,"line":3663},[270,14281,14282],{},"Task: Provide predictive maintenance assessment:\n",[270,14284,14285],{"class":272,"line":3669},[270,14286,14287],{},"1. Motor condition (Normal/Warning/Critical)\n",[270,14289,14290],{"class":272,"line":3675},[270,14291,14292],{},"2. Probable fault type (if any)\n",[270,14294,14295],{"class":272,"line":3681},[270,14296,14297],{},"3. Estimated time to failure (days)\n",[270,14299,14300],{"class":272,"line":3687},[270,14301,13704],{},[270,14303,14304],{"class":272,"line":3693},[270,14305,775],{"emptyLinePlaceholder":524},[270,14307,14308],{"class":272,"line":3698},[270,14309,13713],{},[270,14311,14312],{"class":272,"line":3704},[270,14313,3589],{},[270,14315,14316],{"class":272,"line":3710},[270,14317,775],{"emptyLinePlaceholder":524},[270,14319,14320],{"class":272,"line":3716},[270,14321,13726],{},[270,14323,14324],{"class":272,"line":3721},[270,14325,13731],{},[270,14327,14328],{"class":272,"line":3727},[270,14329,13736],{},[270,14331,14332],{"class":272,"line":3733},[270,14333,14334],{},"            format='json'\n",[270,14336,14337],{"class":272,"line":3739},[270,14338,3766],{},[270,14340,14341],{"class":272,"line":3745},[270,14342,775],{"emptyLinePlaceholder":524},[270,14344,14345],{"class":272,"line":3751},[270,14346,14347],{},"        return json.loads(response['response'])\n",[270,14349,14350],{"class":272,"line":3757},[270,14351,775],{"emptyLinePlaceholder":524},[270,14353,14354],{"class":272,"line":3763},[270,14355,7664],{},[270,14357,14358],{"class":272,"line":3769},[270,14359,14360],{},"    analyzer = VibrationAnalyzer()\n",[270,14362,14363],{"class":272,"line":3774},[270,14364,775],{"emptyLinePlaceholder":524},[270,14366,14367],{"class":272,"line":3780},[270,14368,14369],{},"    # Read vibration data\n",[270,14371,14372],{"class":272,"line":3786},[270,14373,14374],{},"    vibration = analyzer.read_vibration_data(1000)\n",[270,14376,14377],{"class":272,"line":3792},[270,14378,775],{"emptyLinePlaceholder":524},[270,14380,14381],{"class":272,"line":7470},[270,14382,14383],{},"    # Extract features\n",[270,14385,14386],{"class":272,"line":7476},[270,14387,14388],{},"    features = analyzer.extract_features(vibration)\n",[270,14390,14391],{"class":272,"line":7482},[270,14392,14393],{},"    print(f\"📊 Features: {features}\")\n",[270,14395,14396],{"class":272,"line":7488},[270,14397,775],{"emptyLinePlaceholder":524},[270,14399,14400],{"class":272,"line":7494},[270,14401,14402],{},"    # AI prediction\n",[270,14404,14405],{"class":272,"line":7500},[270,14406,14407],{},"    prediction = analyzer.predict_with_ai(features)\n",[270,14409,14410],{"class":272,"line":7506},[270,14411,14412],{},"    print(f\"\\n🔮 AI Prediction:\")\n",[270,14414,14415],{"class":272,"line":7512},[270,14416,14417],{},"    print(json.dumps(prediction, indent=2))\n",[16,14419,14420],{},[93,14421,3800],{},[29,14423,14425],{"className":3803,"code":14424,"language":3805,"meta":38,"style":38},"{\n  \"condition\": \"Warning\",\n  \"fault_type\": \"Bearing wear (outer race)\",\n  \"estimated_ttf_days\": 15,\n  \"confidence\": 0.78,\n  \"recommended_action\": \"Schedule bearing replacement within 2 weeks. Increase monitoring frequency to daily.\",\n  \"evidence\": \"Elevated RMS (3.2 m/s²) and high-frequency components at 250 Hz indicate outer race fault.\"\n}\n",[36,14426,14427,14431,14443,14455,14467,14478,14489,14499],{"__ignoreMap":38},[270,14428,14429],{"class":272,"line":273},[270,14430,3812],{"class":1918},[270,14432,14433,14436,14438,14441],{"class":272,"line":279},[270,14434,14435],{"class":2053},"  \"condition\"",[270,14437,1927],{"class":1918},[270,14439,14440],{"class":1930},"\"Warning\"",[270,14442,3825],{"class":1918},[270,14444,14445,14448,14450,14453],{"class":272,"line":285},[270,14446,14447],{"class":2053},"  \"fault_type\"",[270,14449,1927],{"class":1918},[270,14451,14452],{"class":1930},"\"Bearing wear (outer race)\"",[270,14454,3825],{"class":1918},[270,14456,14457,14460,14462,14465],{"class":272,"line":291},[270,14458,14459],{"class":2053},"  \"estimated_ttf_days\"",[270,14461,1927],{"class":1918},[270,14463,14464],{"class":2053},"15",[270,14466,3825],{"class":1918},[270,14468,14469,14471,14473,14476],{"class":272,"line":297},[270,14470,3878],{"class":2053},[270,14472,1927],{"class":1918},[270,14474,14475],{"class":2053},"0.78",[270,14477,3825],{"class":1918},[270,14479,14480,14482,14484,14487],{"class":272,"line":303},[270,14481,3866],{"class":2053},[270,14483,1927],{"class":1918},[270,14485,14486],{"class":1930},"\"Schedule bearing replacement within 2 weeks. Increase monitoring frequency to daily.\"",[270,14488,3825],{"class":1918},[270,14490,14491,14494,14496],{"class":272,"line":515},[270,14492,14493],{"class":2053},"  \"evidence\"",[270,14495,1927],{"class":1918},[270,14497,14498],{"class":1930},"\"Elevated RMS (3.2 m/s²) and high-frequency components at 250 Hz indicate outer race fault.\"\n",[270,14500,14501],{"class":272,"line":793},[270,14502,2129],{"class":1918},[11,14504,14506],{"id":14505},"raspberry-pi-5-ollama-edge-ai-solution","Raspberry Pi 5 + Ollama: Edge AI Solution",[24,14508,6281],{"id":6280},[16,14510,14511],{},[93,14512,14513],{},"Components:",[40,14515,14516,14519,14522,14525],{},[43,14517,14518],{},"Raspberry Pi 5 (8GB RAM)",[43,14520,14521],{},"NVMe SSD (256GB) via PCIe",[43,14523,14524],{},"PoE+ HAT (for Ethernet power)",[43,14526,14527],{},"Industrial case with fan",[16,14529,14530],{},[93,14531,14532],{},"Performance:",[636,14534,14535,14547],{},[639,14536,14537],{},[642,14538,14539,14541,14544],{},[645,14540,3072],{},[645,14542,14543],{},"Inference Speed",[645,14545,14546],{},"RAM Usage",[655,14548,14549,14562,14575],{},[642,14550,14551,14556,14559],{},[660,14552,14553],{},[93,14554,14555],{},"Llama 3.2 (3B)",[660,14557,14558],{},"~15 tokens/sec",[660,14560,14561],{},"2.5GB",[642,14563,14564,14569,14572],{},[660,14565,14566],{},[93,14567,14568],{},"Phi-3 (3.8B)",[660,14570,14571],{},"~12 tokens/sec",[660,14573,14574],{},"3.2GB",[642,14576,14577,14582,14585],{},[660,14578,14579],{},[93,14580,14581],{},"Mistral 7B",[660,14583,14584],{},"~6 tokens/sec",[660,14586,14587],{},"5.8GB",[24,14589,14591],{"id":14590},"setup-script","Setup Script",[29,14593,14595],{"className":1993,"code":14594,"language":1995,"meta":38,"style":38},"#!/bin/bash\n# install_edge_ai.sh\n\n# Install Ollama on Raspberry Pi 5\ncurl -fsSL https://ollama.com/install.sh | sh\n\n# Download lightweight models\nollama pull llama3.2:3b\nollama pull phi3:mini\n\n# Install Python dependencies\npip3 install ollama pymodbus numpy pandas\n\n# Configure systemd service\ncat > /etc/systemd/system/edge-ai.service \u003C\u003CEOF\n[Unit]\nDescription=Edge AI Monitoring\nAfter=network.target ollama.service\n\n[Service]\nType=simple\nUser=pi\nWorkingDirectory=/opt/edge-ai\nExecStart=/usr/bin/python3 /opt/edge-ai/monitor.py\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsystemctl enable edge-ai\nsystemctl start edge-ai\n",[36,14596,14597,14602,14607,14611,14616,14628,14632,14637,14646,14655,14659,14664,14680,14684,14689,14706,14711,14716,14721,14725,14730,14735,14740,14745,14750,14755,14759,14764,14769,14773,14777,14787],{"__ignoreMap":38},[270,14598,14599],{"class":272,"line":273},[270,14600,14601],{"class":2002},"#!/bin/bash\n",[270,14603,14604],{"class":272,"line":279},[270,14605,14606],{"class":2002},"# install_edge_ai.sh\n",[270,14608,14609],{"class":272,"line":285},[270,14610,775],{"emptyLinePlaceholder":524},[270,14612,14613],{"class":272,"line":291},[270,14614,14615],{"class":2002},"# Install Ollama on Raspberry Pi 5\n",[270,14617,14618,14620,14622,14624,14626],{"class":272,"line":297},[270,14619,12492],{"class":2008},[270,14621,13291],{"class":2053},[270,14623,13294],{"class":1930},[270,14625,13297],{"class":1962},[270,14627,13300],{"class":2008},[270,14629,14630],{"class":272,"line":303},[270,14631,775],{"emptyLinePlaceholder":524},[270,14633,14634],{"class":272,"line":515},[270,14635,14636],{"class":2002},"# Download lightweight models\n",[270,14638,14639,14641,14643],{"class":272,"line":793},[270,14640,13347],{"class":2008},[270,14642,13350],{"class":1930},[270,14644,14645],{"class":1930}," llama3.2:3b\n",[270,14647,14648,14650,14652],{"class":272,"line":799},[270,14649,13347],{"class":2008},[270,14651,13350],{"class":1930},[270,14653,14654],{"class":1930}," phi3:mini\n",[270,14656,14657],{"class":272,"line":805},[270,14658,775],{"emptyLinePlaceholder":524},[270,14660,14661],{"class":272,"line":2120},[270,14662,14663],{"class":2002},"# Install Python dependencies\n",[270,14665,14666,14669,14671,14673,14675,14678],{"class":272,"line":2126},[270,14667,14668],{"class":2008},"pip3",[270,14670,2015],{"class":1930},[270,14672,13415],{"class":1930},[270,14674,13421],{"class":1930},[270,14676,14677],{"class":1930}," numpy",[270,14679,13427],{"class":1930},[270,14681,14682],{"class":272,"line":2132},[270,14683,775],{"emptyLinePlaceholder":524},[270,14685,14686],{"class":272,"line":3375},[270,14687,14688],{"class":2002},"# Configure systemd service\n",[270,14690,14691,14694,14697,14700,14703],{"class":272,"line":3381},[270,14692,14693],{"class":2008},"cat",[270,14695,14696],{"class":1962}," >",[270,14698,14699],{"class":1930}," /etc/systemd/system/edge-ai.service",[270,14701,14702],{"class":1962}," \u003C\u003C",[270,14704,14705],{"class":1930},"EOF\n",[270,14707,14708],{"class":272,"line":3387},[270,14709,14710],{"class":1930},"[Unit]\n",[270,14712,14713],{"class":272,"line":3393},[270,14714,14715],{"class":1930},"Description=Edge AI Monitoring\n",[270,14717,14718],{"class":272,"line":3399},[270,14719,14720],{"class":1930},"After=network.target ollama.service\n",[270,14722,14723],{"class":272,"line":3405},[270,14724,775],{"emptyLinePlaceholder":524},[270,14726,14727],{"class":272,"line":3411},[270,14728,14729],{"class":1930},"[Service]\n",[270,14731,14732],{"class":272,"line":3417},[270,14733,14734],{"class":1930},"Type=simple\n",[270,14736,14737],{"class":272,"line":3423},[270,14738,14739],{"class":1930},"User=pi\n",[270,14741,14742],{"class":272,"line":3429},[270,14743,14744],{"class":1930},"WorkingDirectory=/opt/edge-ai\n",[270,14746,14747],{"class":272,"line":3434},[270,14748,14749],{"class":1930},"ExecStart=/usr/bin/python3 /opt/edge-ai/monitor.py\n",[270,14751,14752],{"class":272,"line":3440},[270,14753,14754],{"class":1930},"Restart=always\n",[270,14756,14757],{"class":272,"line":3446},[270,14758,775],{"emptyLinePlaceholder":524},[270,14760,14761],{"class":272,"line":3452},[270,14762,14763],{"class":1930},"[Install]\n",[270,14765,14766],{"class":272,"line":3457},[270,14767,14768],{"class":1930},"WantedBy=multi-user.target\n",[270,14770,14771],{"class":272,"line":3463},[270,14772,14705],{"class":1930},[270,14774,14775],{"class":272,"line":3469},[270,14776,775],{"emptyLinePlaceholder":524},[270,14778,14779,14782,14784],{"class":272,"line":3475},[270,14780,14781],{"class":2008},"systemctl",[270,14783,13331],{"class":1930},[270,14785,14786],{"class":1930}," edge-ai\n",[270,14788,14789,14791,14793],{"class":272,"line":3480},[270,14790,14781],{"class":2008},[270,14792,13319],{"class":1930},[270,14794,14786],{"class":1930},[11,14796,14798],{"id":14797},"cost-comparison-ollama-vs-cloud-ai","Cost Comparison: Ollama vs Cloud AI",[24,14800,14802],{"id":14801},"scenario-10-devices-continuous-monitoring","Scenario: 10 devices, continuous monitoring",[16,14804,14805],{},[93,14806,14807],{},"Monthly Costs:",[636,14809,14810,14826],{},[639,14811,14812],{},[642,14813,14814,14817,14820,14823],{},[645,14815,14816],{},"Solution",[645,14818,14819],{},"Hardware",[645,14821,14822],{},"Compute",[645,14824,14825],{},"Total",[655,14827,14828,14841,14854],{},[642,14829,14830,14834,14836,14839],{},[660,14831,14832],{},[93,14833,3041],{},[660,14835,3143],{},[660,14837,14838],{},"$450/month",[660,14840,14838],{},[642,14842,14843,14847,14849,14852],{},[660,14844,14845],{},[93,14846,3179],{},[660,14848,3143],{},[660,14850,14851],{},"$820/month",[660,14853,14851],{},[642,14855,14856,14860,14863,14866],{},[660,14857,14858],{},[93,14859,13171],{},[660,14861,14862],{},"$800 (one-time)",[660,14864,14865],{},"$5 (electricity)",[660,14867,14868],{},[93,14869,14870],{},"$5/month",[16,14872,14873,14876],{},[93,14874,14875],{},"ROI:"," Ollama pays for itself in 2 months!",[11,14878,444],{"id":443},[16,14880,14881,14883,14884,14887],{},[93,14882,13094],{}," enables powerful AI applications in industrial facilities while maintaining ",[93,14885,14886],{},"complete data privacy",". Especially for:",[16,14889,5091,14890,14893,5098,14895,14898,5098,14900,14903,5098,14905],{},[93,14891,14892],{},"Factories with confidential production data",[2353,14894],{},[93,14896,14897],{},"Facilities without reliable internet",[2353,14899],{},[93,14901,14902],{},"Real-time decision making requirements (\u003C100ms)",[2353,14904],{},[93,14906,14907],{},"Cost-sensitive projects",[16,14909,1718,14910,467,14912,14914,14915,472],{},[463,14911,1360],{"href":1613},[463,14913,2840],{"href":1723}," products can be combined with Ollama to build predictive maintenance systems ",[93,14916,14917],{},"entirely locally",[24,14919,5132],{"id":5131},[40,14921,14922,14928,14934,14938],{},[43,14923,14924,14927],{},[463,14925,14926],{"href":5197},"Industrial AI with AWS Bedrock"," (Cloud alternative)",[43,14929,14930,14933],{},[463,14931,14932],{"href":1646},"TinyML: AI Revolution in Industrial Sensors"," (MCU-level AI)",[43,14935,14936],{},[463,14937,466],{"href":1613},[43,14939,14940],{},[463,14941,471],{"href":1723},[477,14943,14944],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":38,"searchDepth":279,"depth":279,"links":14946},[14947,14948,14952,14953,14957,14961,14965,14969,14972],{"id":13,"depth":279,"text":14},{"id":13113,"depth":279,"text":13114,"children":14949},[14950,14951],{"id":11452,"depth":285,"text":11453},{"id":13154,"depth":285,"text":13155},{"id":3279,"depth":279,"text":3280},{"id":13269,"depth":279,"text":13270,"children":14954},[14955,14956],{"id":13273,"depth":285,"text":13274},{"id":13399,"depth":285,"text":13400},{"id":13430,"depth":279,"text":13431,"children":14958},[14959,14960],{"id":3293,"depth":285,"text":3294},{"id":13456,"depth":285,"text":13457},{"id":13960,"depth":279,"text":13961,"children":14962},[14963,14964],{"id":3894,"depth":285,"text":3294},{"id":13972,"depth":285,"text":13973},{"id":14505,"depth":279,"text":14506,"children":14966},[14967,14968],{"id":6280,"depth":285,"text":6281},{"id":14590,"depth":285,"text":14591},{"id":14797,"depth":279,"text":14798,"children":14970},[14971],{"id":14801,"depth":285,"text":14802},{"id":443,"depth":279,"text":444,"children":14973},[14974],{"id":5131,"depth":285,"text":5132},"Local AI models deployment with Ollama in factories without cloud data transfer for predictive maintenance and anomaly detection applications.",{"date":3011,"author":514,"readTime":2120,"tags":14977},[13094,14978,14979,5193,1642,3207,5194],"Local AI","Predictive Maintenance",{"title":13071,"description":14975},"en/blog/on-premise-ai-solutions-with-ollama","mKxsuIH4_TTq3ryFkBdo491ZQAH_cjoLLC8AQhLeSE0",{"id":14984,"title":2377,"body":14985,"description":16941,"extension":511,"meta":16942,"navigation":524,"path":1758,"seo":16948,"stem":16949,"__hash__":16950},"en_blog/en/blog/time-series-data-management-amazon-timestream.md",{"type":8,"value":14986,"toc":16910},[14987,14989,14999,15007,15011,15017,15021,15047,15051,15131,15133,15139,15143,15147,15237,15242,15256,15260,15265,15302,15307,15406,15410,15414,15791,15795,15799,15804,15855,15860,15915,15920,16040,16044,16049,16203,16208,16265,16269,16273,16278,16296,16301,16438,16442,16447,16502,16507,16521,16523,16527,16593,16597,16602,16641,16646,16703,16708,16751,16755,16760,16838,16841,16843,16848,16877,16887,16889,16907],[11,14988,14],{"id":13},[16,14990,14991,14992,14995,14996,14998],{},"Traditional relational databases (PostgreSQL, MySQL) are not optimized for ",[93,14993,14994],{},"time series data"," from industrial sensors. ",[93,14997,1754],{}," is a fully managed time series database offering 10x faster writes and 1/10 the cost.",[16,15000,15001,15002,467,15004,15006],{},"In this article, we examine how to efficiently store and analyze data from our ",[463,15003,466],{"href":1613},[463,15005,471],{"href":1723}," devices using AWS Timestream.",[11,15008,15010],{"id":15009},"what-is-time-series-data","What is Time Series Data?",[16,15012,15013,15016],{},[93,15014,15015],{},"Time series data:"," Data points recorded at sequential time intervals.",[24,15018,15020],{"id":15019},"industrial-examples","Industrial Examples",[40,15022,15023,15029,15035,15041],{},[43,15024,15025,15028],{},[93,15026,15027],{},"Weight measurement:"," Tank weight every second",[43,15030,15031,15034],{},[93,15032,15033],{},"Temperature:"," Oven temperature every 5 seconds",[43,15036,15037,15040],{},[93,15038,15039],{},"Vibration:"," Motor vibration 1000 samples/second",[43,15042,15043,15046],{},[93,15044,15045],{},"Energy consumption:"," Power meter every 15 minutes",[24,15048,15050],{"id":15049},"relational-db-vs-time-series-db","Relational DB vs Time Series DB",[636,15052,15053,15064],{},[639,15054,15055],{},[642,15056,15057,15059,15062],{},[645,15058,647],{},[645,15060,15061],{},"PostgreSQL",[645,15063,1754],{},[655,15065,15066,15079,15092,15105,15118],{},[642,15067,15068,15073,15076],{},[660,15069,15070],{},[93,15071,15072],{},"Write Speed",[660,15074,15075],{},"~10K/sec",[660,15077,15078],{},"~100K/sec",[642,15080,15081,15086,15089],{},[660,15082,15083],{},[93,15084,15085],{},"Compression",[660,15087,15088],{},"~30%",[660,15090,15091],{},"~90% (10x better)",[642,15093,15094,15099,15102],{},[660,15095,15096],{},[93,15097,15098],{},"Time Queries",[660,15100,15101],{},"Complex SQL",[660,15103,15104],{},"Native time functions",[642,15106,15107,15112,15115],{},[660,15108,15109],{},[93,15110,15111],{},"Auto-Tiering",[660,15113,15114],{},"Manual partitioning",[660,15116,15117],{},"Automatic (Memory→Magnetic)",[642,15119,15120,15125,15128],{},[660,15121,15122],{},[93,15123,15124],{},"Cost (1TB/month)",[660,15126,15127],{},"~$200",[660,15129,15130],{},"~$20",[11,15132,3280],{"id":3279},[29,15134,15137],{"className":15135,"code":15136,"language":34},[32],"┌─────────────────────────────────────────────────┐\n│              Factory Network                    │\n│                                                 │\n│  ┌─────────┐    Modbus TCP   ┌──────────────┐  │\n│  │ ZMA/GDT │◄────────────────►│  IoT Gateway │  │\n│  │ Devices │                  │ (Python)     │  │\n│  └─────────┘                  └──────┬───────┘  │\n└─────────────────────────────────────┼───────────┘\n                                      │ MQTT\n                                      │ TLS 8883\n                                      ▼\n                         ┌────────────────────────┐\n                         │      AWS Cloud         │\n                         │                        │\n                         │  ┌──────────────────┐  │\n                         │  │   IoT Core       │  │\n                         │  └────────┬─────────┘  │\n                         │           │            │\n                         │  ┌────────▼─────────┐  │\n                         │  │   Timestream     │  │\n                         │  │   Database       │  │\n                         │  │                  │  │\n                         │  │  Memory Store    │  │\n                         │  │  (Recent data)   │  │\n                         │  │        ▼         │  │\n                         │  │  Magnetic Store  │  │\n                         │  │  (Historical)    │  │\n                         │  └────────┬─────────┘  │\n                         │           │            │\n                         │  ┌────────▼─────────┐  │\n                         │  │    Grafana       │  │\n                         │  │   Dashboards     │  │\n                         │  └──────────────────┘  │\n                         └────────────────────────┘\n",[36,15138,15136],{"__ignoreMap":38},[11,15140,15142],{"id":15141},"timestream-database-setup","Timestream Database Setup",[24,15144,15146],{"id":15145},"_1-create-database-and-table","1. Create Database and Table",[29,15148,15150],{"className":1993,"code":15149,"language":1995,"meta":38,"style":38},"# Create database\naws timestream-write create-database \\\n  --database-name FactoryData\n\n# Create table\naws timestream-write create-table \\\n  --database-name FactoryData \\\n  --table-name TankWeights \\\n  --retention-properties '{\n    \"MemoryStoreRetentionPeriodInHours\": 24,\n    \"MagneticStoreRetentionPeriodInDays\": 90\n  }'\n",[36,15151,15152,15157,15169,15177,15181,15186,15197,15206,15216,15223,15228,15233],{"__ignoreMap":38},[270,15153,15154],{"class":272,"line":273},[270,15155,15156],{"class":2002},"# Create database\n",[270,15158,15159,15161,15164,15167],{"class":272,"line":279},[270,15160,10445],{"class":2008},[270,15162,15163],{"class":1930}," timestream-write",[270,15165,15166],{"class":1930}," create-database",[270,15168,10454],{"class":2053},[270,15170,15171,15174],{"class":272,"line":285},[270,15172,15173],{"class":2053},"  --database-name",[270,15175,15176],{"class":1930}," FactoryData\n",[270,15178,15179],{"class":272,"line":291},[270,15180,775],{"emptyLinePlaceholder":524},[270,15182,15183],{"class":272,"line":297},[270,15184,15185],{"class":2002},"# Create table\n",[270,15187,15188,15190,15192,15195],{"class":272,"line":303},[270,15189,10445],{"class":2008},[270,15191,15163],{"class":1930},[270,15193,15194],{"class":1930}," create-table",[270,15196,10454],{"class":2053},[270,15198,15199,15201,15204],{"class":272,"line":515},[270,15200,15173],{"class":2053},[270,15202,15203],{"class":1930}," FactoryData",[270,15205,10454],{"class":2053},[270,15207,15208,15211,15214],{"class":272,"line":793},[270,15209,15210],{"class":2053},"  --table-name",[270,15212,15213],{"class":1930}," TankWeights",[270,15215,10454],{"class":2053},[270,15217,15218,15221],{"class":272,"line":799},[270,15219,15220],{"class":2053},"  --retention-properties",[270,15222,12530],{"class":1930},[270,15224,15225],{"class":272,"line":805},[270,15226,15227],{"class":1930},"    \"MemoryStoreRetentionPeriodInHours\": 24,\n",[270,15229,15230],{"class":272,"line":2120},[270,15231,15232],{"class":1930},"    \"MagneticStoreRetentionPeriodInDays\": 90\n",[270,15234,15235],{"class":272,"line":2126},[270,15236,12565],{"class":1930},[16,15238,15239],{},[93,15240,15241],{},"Retention Policy:",[40,15243,15244,15250],{},[43,15245,15246,15249],{},[93,15247,15248],{},"Memory Store (24 hours):"," Fast queries for recent data",[43,15251,15252,15255],{},[93,15253,15254],{},"Magnetic Store (90 days):"," Cost-effective long-term storage",[24,15257,15259],{"id":15258},"_2-iot-core-rule-to-write-to-timestream","2. IoT Core Rule to Write to Timestream",[16,15261,15262],{},[93,15263,15264],{},"IoT Rule SQL:",[29,15266,15268],{"className":1819,"code":15267,"language":1821,"meta":38,"style":38},"SELECT\n  device_name as device_id,\n  values.net_weight as weight,\n  values.temperature as temperature,\n  timestamp\nFROM\n  'amazeng/factory/tank/+/data'\n",[36,15269,15270,15274,15279,15284,15289,15293,15297],{"__ignoreMap":38},[270,15271,15272],{"class":272,"line":273},[270,15273,7699],{},[270,15275,15276],{"class":272,"line":279},[270,15277,15278],{},"  device_name as device_id,\n",[270,15280,15281],{"class":272,"line":285},[270,15282,15283],{},"  values.net_weight as weight,\n",[270,15285,15286],{"class":272,"line":291},[270,15287,15288],{},"  values.temperature as temperature,\n",[270,15290,15291],{"class":272,"line":297},[270,15292,7714],{},[270,15294,15295],{"class":272,"line":303},[270,15296,7719],{},[270,15298,15299],{"class":272,"line":515},[270,15300,15301],{},"  'amazeng/factory/tank/+/data'\n",[16,15303,15304,15306],{},[93,15305,7739],{}," Timestream",[29,15308,15310],{"className":3803,"code":15309,"language":3805,"meta":38,"style":38},"{\n  \"databaseName\": \"FactoryData\",\n  \"tableName\": \"TankWeights\",\n  \"dimensions\": [{ \"name\": \"device_id\", \"value\": \"${device_id}\" }],\n  \"timestamp\": {\n    \"value\": \"${timestamp}\",\n    \"unit\": \"MILLISECONDS\"\n  }\n}\n",[36,15311,15312,15316,15328,15340,15369,15376,15388,15398,15402],{"__ignoreMap":38},[270,15313,15314],{"class":272,"line":273},[270,15315,3812],{"class":1918},[270,15317,15318,15321,15323,15326],{"class":272,"line":279},[270,15319,15320],{"class":2053},"  \"databaseName\"",[270,15322,1927],{"class":1918},[270,15324,15325],{"class":1930},"\"FactoryData\"",[270,15327,3825],{"class":1918},[270,15329,15330,15333,15335,15338],{"class":272,"line":285},[270,15331,15332],{"class":2053},"  \"tableName\"",[270,15334,1927],{"class":1918},[270,15336,15337],{"class":1930},"\"TankWeights\"",[270,15339,3825],{"class":1918},[270,15341,15342,15345,15348,15351,15353,15356,15358,15361,15363,15366],{"class":272,"line":291},[270,15343,15344],{"class":2053},"  \"dimensions\"",[270,15346,15347],{"class":1918},": [{ ",[270,15349,15350],{"class":2053},"\"name\"",[270,15352,1927],{"class":1918},[270,15354,15355],{"class":1930},"\"device_id\"",[270,15357,6180],{"class":1918},[270,15359,15360],{"class":2053},"\"value\"",[270,15362,1927],{"class":1918},[270,15364,15365],{"class":1930},"\"${device_id}\"",[270,15367,15368],{"class":1918}," }],\n",[270,15370,15371,15374],{"class":272,"line":297},[270,15372,15373],{"class":2053},"  \"timestamp\"",[270,15375,6468],{"class":1918},[270,15377,15378,15381,15383,15386],{"class":272,"line":303},[270,15379,15380],{"class":2053},"    \"value\"",[270,15382,1927],{"class":1918},[270,15384,15385],{"class":1930},"\"${timestamp}\"",[270,15387,3825],{"class":1918},[270,15389,15390,15393,15395],{"class":272,"line":515},[270,15391,15392],{"class":2053},"    \"unit\"",[270,15394,1927],{"class":1918},[270,15396,15397],{"class":1930},"\"MILLISECONDS\"\n",[270,15399,15400],{"class":272,"line":793},[270,15401,6564],{"class":1918},[270,15403,15404],{"class":272,"line":799},[270,15405,2129],{"class":1918},[11,15407,15409],{"id":15408},"data-ingestion-python-example","Data Ingestion: Python Example",[24,15411,15413],{"id":15412},"write-data-to-timestream","Write Data to Timestream",[29,15415,15417],{"className":751,"code":15416,"language":753,"meta":38,"style":38},"import boto3\nimport time\nfrom datetime import datetime\n\nclass TimestreamWriter:\n    def __init__(self, database_name, table_name):\n        self.client = boto3.client('timestream-write', region_name='eu-west-1')\n        self.database = database_name\n        self.table = table_name\n\n    def write_weight_data(self, tank_id, weight, temperature):\n        \"\"\"Write single measurement\"\"\"\n        current_time = str(int(time.time() * 1000))  # Milliseconds\n\n        records = [\n            {\n                'Dimensions': [\n                    {'Name': 'tank_id', 'Value': str(tank_id)},\n                    {'Name': 'location', 'Value': 'Istanbul-Factory'},\n                ],\n                'MeasureName': 'metrics',\n                'MeasureValues': [\n                    {'Name': 'weight', 'Value': str(weight), 'Type': 'DOUBLE'},\n                    {'Name': 'temperature', 'Value': str(temperature), 'Type': 'DOUBLE'}\n                ],\n                'MeasureValueType': 'MULTI',\n                'Time': current_time\n            }\n        ]\n\n        try:\n            result = self.client.write_records(\n                DatabaseName=self.database,\n                TableName=self.table,\n                Records=records\n            )\n            print(f\"✓ Written: Tank {tank_id} - {weight} kg\")\n            return result\n        except Exception as e:\n            print(f\"✗ Error: {e}\")\n            return None\n\n    def write_batch(self, data_list):\n        \"\"\"Write multiple measurements (up to 100)\"\"\"\n        records = []\n        current_time = str(int(time.time() * 1000))\n\n        for data in data_list:\n            records.append({\n                'Dimensions': [\n                    {'Name': 'tank_id', 'Value': str(data['tank_id'])},\n                ],\n                'MeasureName': 'weight',\n                'MeasureValue': str(data['weight']),\n                'MeasureValueType': 'DOUBLE',\n                'Time': current_time\n            })\n\n        result = self.client.write_records(\n            DatabaseName=self.database,\n            TableName=self.table,\n            Records=records\n        )\n\n        return result\n\n# Usage\nwriter = TimestreamWriter('FactoryData', 'TankWeights')\n\n# Single write\nwriter.write_weight_data(tank_id=1, weight=4523.5, temperature=4.2)\n\n# Batch write\nbatch_data = [\n    {'tank_id': 1, 'weight': 4523.5},\n    {'tank_id': 2, 'weight': 3890.2},\n    {'tank_id': 3, 'weight': 4102.8}\n]\nwriter.write_batch(batch_data)\n",[36,15418,15419,15423,15427,15431,15435,15440,15445,15450,15455,15460,15464,15469,15474,15479,15483,15488,15493,15498,15503,15508,15513,15518,15523,15528,15533,15537,15542,15547,15551,15555,15559,15563,15568,15573,15578,15583,15588,15593,15598,15603,15608,15613,15617,15622,15627,15632,15637,15641,15646,15651,15655,15660,15664,15669,15674,15679,15683,15688,15692,15697,15702,15707,15712,15716,15720,15724,15728,15733,15738,15742,15747,15752,15756,15761,15766,15771,15776,15781,15786],{"__ignoreMap":38},[270,15420,15421],{"class":272,"line":273},[270,15422,3314],{},[270,15424,15425],{"class":272,"line":279},[270,15426,7075],{},[270,15428,15429],{"class":272,"line":285},[270,15430,7080],{},[270,15432,15433],{"class":272,"line":291},[270,15434,775],{"emptyLinePlaceholder":524},[270,15436,15437],{"class":272,"line":297},[270,15438,15439],{},"class TimestreamWriter:\n",[270,15441,15442],{"class":272,"line":303},[270,15443,15444],{},"    def __init__(self, database_name, table_name):\n",[270,15446,15447],{"class":272,"line":515},[270,15448,15449],{},"        self.client = boto3.client('timestream-write', region_name='eu-west-1')\n",[270,15451,15452],{"class":272,"line":793},[270,15453,15454],{},"        self.database = database_name\n",[270,15456,15457],{"class":272,"line":799},[270,15458,15459],{},"        self.table = table_name\n",[270,15461,15462],{"class":272,"line":805},[270,15463,775],{"emptyLinePlaceholder":524},[270,15465,15466],{"class":272,"line":2120},[270,15467,15468],{},"    def write_weight_data(self, tank_id, weight, temperature):\n",[270,15470,15471],{"class":272,"line":2126},[270,15472,15473],{},"        \"\"\"Write single measurement\"\"\"\n",[270,15475,15476],{"class":272,"line":2132},[270,15477,15478],{},"        current_time = str(int(time.time() * 1000))  # Milliseconds\n",[270,15480,15481],{"class":272,"line":3375},[270,15482,775],{"emptyLinePlaceholder":524},[270,15484,15485],{"class":272,"line":3381},[270,15486,15487],{},"        records = [\n",[270,15489,15490],{"class":272,"line":3387},[270,15491,15492],{},"            {\n",[270,15494,15495],{"class":272,"line":3393},[270,15496,15497],{},"                'Dimensions': [\n",[270,15499,15500],{"class":272,"line":3399},[270,15501,15502],{},"                    {'Name': 'tank_id', 'Value': str(tank_id)},\n",[270,15504,15505],{"class":272,"line":3405},[270,15506,15507],{},"                    {'Name': 'location', 'Value': 'Istanbul-Factory'},\n",[270,15509,15510],{"class":272,"line":3411},[270,15511,15512],{},"                ],\n",[270,15514,15515],{"class":272,"line":3417},[270,15516,15517],{},"                'MeasureName': 'metrics',\n",[270,15519,15520],{"class":272,"line":3423},[270,15521,15522],{},"                'MeasureValues': [\n",[270,15524,15525],{"class":272,"line":3429},[270,15526,15527],{},"                    {'Name': 'weight', 'Value': str(weight), 'Type': 'DOUBLE'},\n",[270,15529,15530],{"class":272,"line":3434},[270,15531,15532],{},"                    {'Name': 'temperature', 'Value': str(temperature), 'Type': 'DOUBLE'}\n",[270,15534,15535],{"class":272,"line":3440},[270,15536,15512],{},[270,15538,15539],{"class":272,"line":3446},[270,15540,15541],{},"                'MeasureValueType': 'MULTI',\n",[270,15543,15544],{"class":272,"line":3452},[270,15545,15546],{},"                'Time': current_time\n",[270,15548,15549],{"class":272,"line":3457},[270,15550,4592],{},[270,15552,15553],{"class":272,"line":3463},[270,15554,7134],{},[270,15556,15557],{"class":272,"line":3469},[270,15558,775],{"emptyLinePlaceholder":524},[270,15560,15561],{"class":272,"line":3475},[270,15562,7555],{},[270,15564,15565],{"class":272,"line":3480},[270,15566,15567],{},"            result = self.client.write_records(\n",[270,15569,15570],{"class":272,"line":3486},[270,15571,15572],{},"                DatabaseName=self.database,\n",[270,15574,15575],{"class":272,"line":3492},[270,15576,15577],{},"                TableName=self.table,\n",[270,15579,15580],{"class":272,"line":3497},[270,15581,15582],{},"                Records=records\n",[270,15584,15585],{"class":272,"line":3503},[270,15586,15587],{},"            )\n",[270,15589,15590],{"class":272,"line":3509},[270,15591,15592],{},"            print(f\"✓ Written: Tank {tank_id} - {weight} kg\")\n",[270,15594,15595],{"class":272,"line":3515},[270,15596,15597],{},"            return result\n",[270,15599,15600],{"class":272,"line":3521},[270,15601,15602],{},"        except Exception as e:\n",[270,15604,15605],{"class":272,"line":3527},[270,15606,15607],{},"            print(f\"✗ Error: {e}\")\n",[270,15609,15610],{"class":272,"line":3532},[270,15611,15612],{},"            return None\n",[270,15614,15615],{"class":272,"line":3538},[270,15616,775],{"emptyLinePlaceholder":524},[270,15618,15619],{"class":272,"line":3544},[270,15620,15621],{},"    def write_batch(self, data_list):\n",[270,15623,15624],{"class":272,"line":3550},[270,15625,15626],{},"        \"\"\"Write multiple measurements (up to 100)\"\"\"\n",[270,15628,15629],{"class":272,"line":3556},[270,15630,15631],{},"        records = []\n",[270,15633,15634],{"class":272,"line":3562},[270,15635,15636],{},"        current_time = str(int(time.time() * 1000))\n",[270,15638,15639],{"class":272,"line":3568},[270,15640,775],{"emptyLinePlaceholder":524},[270,15642,15643],{"class":272,"line":3574},[270,15644,15645],{},"        for data in data_list:\n",[270,15647,15648],{"class":272,"line":3580},[270,15649,15650],{},"            records.append({\n",[270,15652,15653],{"class":272,"line":3586},[270,15654,15497],{},[270,15656,15657],{"class":272,"line":3592},[270,15658,15659],{},"                    {'Name': 'tank_id', 'Value': str(data['tank_id'])},\n",[270,15661,15662],{"class":272,"line":3597},[270,15663,15512],{},[270,15665,15666],{"class":272,"line":3603},[270,15667,15668],{},"                'MeasureName': 'weight',\n",[270,15670,15671],{"class":272,"line":3609},[270,15672,15673],{},"                'MeasureValue': str(data['weight']),\n",[270,15675,15676],{"class":272,"line":3615},[270,15677,15678],{},"                'MeasureValueType': 'DOUBLE',\n",[270,15680,15681],{"class":272,"line":3621},[270,15682,15546],{},[270,15684,15685],{"class":272,"line":3627},[270,15686,15687],{},"            })\n",[270,15689,15690],{"class":272,"line":3633},[270,15691,775],{"emptyLinePlaceholder":524},[270,15693,15694],{"class":272,"line":3639},[270,15695,15696],{},"        result = self.client.write_records(\n",[270,15698,15699],{"class":272,"line":3645},[270,15700,15701],{},"            DatabaseName=self.database,\n",[270,15703,15704],{"class":272,"line":3651},[270,15705,15706],{},"            TableName=self.table,\n",[270,15708,15709],{"class":272,"line":3657},[270,15710,15711],{},"            Records=records\n",[270,15713,15714],{"class":272,"line":3663},[270,15715,3766],{},[270,15717,15718],{"class":272,"line":3669},[270,15719,775],{"emptyLinePlaceholder":524},[270,15721,15722],{"class":272,"line":3675},[270,15723,13759],{},[270,15725,15726],{"class":272,"line":3681},[270,15727,775],{"emptyLinePlaceholder":524},[270,15729,15730],{"class":272,"line":3687},[270,15731,15732],{},"# Usage\n",[270,15734,15735],{"class":272,"line":3693},[270,15736,15737],{},"writer = TimestreamWriter('FactoryData', 'TankWeights')\n",[270,15739,15740],{"class":272,"line":3698},[270,15741,775],{"emptyLinePlaceholder":524},[270,15743,15744],{"class":272,"line":3704},[270,15745,15746],{},"# Single write\n",[270,15748,15749],{"class":272,"line":3710},[270,15750,15751],{},"writer.write_weight_data(tank_id=1, weight=4523.5, temperature=4.2)\n",[270,15753,15754],{"class":272,"line":3716},[270,15755,775],{"emptyLinePlaceholder":524},[270,15757,15758],{"class":272,"line":3721},[270,15759,15760],{},"# Batch write\n",[270,15762,15763],{"class":272,"line":3727},[270,15764,15765],{},"batch_data = [\n",[270,15767,15768],{"class":272,"line":3733},[270,15769,15770],{},"    {'tank_id': 1, 'weight': 4523.5},\n",[270,15772,15773],{"class":272,"line":3739},[270,15774,15775],{},"    {'tank_id': 2, 'weight': 3890.2},\n",[270,15777,15778],{"class":272,"line":3745},[270,15779,15780],{},"    {'tank_id': 3, 'weight': 4102.8}\n",[270,15782,15783],{"class":272,"line":3751},[270,15784,15785],{},"]\n",[270,15787,15788],{"class":272,"line":3757},[270,15789,15790],{},"writer.write_batch(batch_data)\n",[11,15792,15794],{"id":15793},"querying-data-with-sql","Querying Data with SQL",[24,15796,15798],{"id":15797},"basic-queries","Basic Queries",[16,15800,15801],{},[93,15802,15803],{},"1. Latest Weight per Tank:",[29,15805,15807],{"className":1819,"code":15806,"language":1821,"meta":38,"style":38},"SELECT\n  tank_id,\n  measure_value::double as weight,\n  time\nFROM\n  \"FactoryData\".\"TankWeights\"\nWHERE\n  time > ago(5m)\nORDER BY\n  time DESC\n",[36,15808,15809,15813,15817,15822,15827,15831,15836,15840,15845,15850],{"__ignoreMap":38},[270,15810,15811],{"class":272,"line":273},[270,15812,7699],{},[270,15814,15815],{"class":272,"line":279},[270,15816,7704],{},[270,15818,15819],{"class":272,"line":285},[270,15820,15821],{},"  measure_value::double as weight,\n",[270,15823,15824],{"class":272,"line":291},[270,15825,15826],{},"  time\n",[270,15828,15829],{"class":272,"line":297},[270,15830,7719],{},[270,15832,15833],{"class":272,"line":303},[270,15834,15835],{},"  \"FactoryData\".\"TankWeights\"\n",[270,15837,15838],{"class":272,"line":515},[270,15839,7729],{},[270,15841,15842],{"class":272,"line":793},[270,15843,15844],{},"  time > ago(5m)\n",[270,15846,15847],{"class":272,"line":799},[270,15848,15849],{},"ORDER BY\n",[270,15851,15852],{"class":272,"line":805},[270,15853,15854],{},"  time DESC\n",[16,15856,15857],{},[93,15858,15859],{},"2. Average Weight (Last Hour):",[29,15861,15863],{"className":1819,"code":15862,"language":1821,"meta":38,"style":38},"SELECT\n  tank_id,\n  AVG(measure_value::double) as avg_weight,\n  COUNT(*) as sample_count\nFROM\n  \"FactoryData\".\"TankWeights\"\nWHERE\n  time > ago(1h)\n  AND measure_name = 'weight'\nGROUP BY\n  tank_id\n",[36,15864,15865,15869,15873,15878,15883,15887,15891,15895,15900,15905,15910],{"__ignoreMap":38},[270,15866,15867],{"class":272,"line":273},[270,15868,7699],{},[270,15870,15871],{"class":272,"line":279},[270,15872,7704],{},[270,15874,15875],{"class":272,"line":285},[270,15876,15877],{},"  AVG(measure_value::double) as avg_weight,\n",[270,15879,15880],{"class":272,"line":291},[270,15881,15882],{},"  COUNT(*) as sample_count\n",[270,15884,15885],{"class":272,"line":297},[270,15886,7719],{},[270,15888,15889],{"class":272,"line":303},[270,15890,15835],{},[270,15892,15893],{"class":272,"line":515},[270,15894,7729],{},[270,15896,15897],{"class":272,"line":793},[270,15898,15899],{},"  time > ago(1h)\n",[270,15901,15902],{"class":272,"line":799},[270,15903,15904],{},"  AND measure_name = 'weight'\n",[270,15906,15907],{"class":272,"line":805},[270,15908,15909],{},"GROUP BY\n",[270,15911,15912],{"class":272,"line":2120},[270,15913,15914],{},"  tank_id\n",[16,15916,15917],{},[93,15918,15919],{},"3. Fill Rate (kg/hour):",[29,15921,15923],{"className":1819,"code":15922,"language":1821,"meta":38,"style":38},"WITH binned_data AS (\n  SELECT\n    tank_id,\n    bin(time, 1h) as hour_bin,\n    AVG(measure_value::double) as avg_weight\n  FROM\n    \"FactoryData\".\"TankWeights\"\n  WHERE\n    time > ago(24h)\n  GROUP BY\n    tank_id, bin(time, 1h)\n)\nSELECT\n  tank_id,\n  hour_bin,\n  avg_weight,\n  avg_weight - LAG(avg_weight) OVER (\n    PARTITION BY tank_id\n    ORDER BY hour_bin\n  ) as fill_rate_per_hour\nFROM\n  binned_data\nORDER BY\n  tank_id, hour_bin DESC\n",[36,15924,15925,15930,15935,15940,15945,15950,15955,15960,15965,15970,15975,15980,15984,15988,15992,15997,16002,16007,16012,16017,16022,16026,16031,16035],{"__ignoreMap":38},[270,15926,15927],{"class":272,"line":273},[270,15928,15929],{},"WITH binned_data AS (\n",[270,15931,15932],{"class":272,"line":279},[270,15933,15934],{},"  SELECT\n",[270,15936,15937],{"class":272,"line":285},[270,15938,15939],{},"    tank_id,\n",[270,15941,15942],{"class":272,"line":291},[270,15943,15944],{},"    bin(time, 1h) as hour_bin,\n",[270,15946,15947],{"class":272,"line":297},[270,15948,15949],{},"    AVG(measure_value::double) as avg_weight\n",[270,15951,15952],{"class":272,"line":303},[270,15953,15954],{},"  FROM\n",[270,15956,15957],{"class":272,"line":515},[270,15958,15959],{},"    \"FactoryData\".\"TankWeights\"\n",[270,15961,15962],{"class":272,"line":793},[270,15963,15964],{},"  WHERE\n",[270,15966,15967],{"class":272,"line":799},[270,15968,15969],{},"    time > ago(24h)\n",[270,15971,15972],{"class":272,"line":805},[270,15973,15974],{},"  GROUP BY\n",[270,15976,15977],{"class":272,"line":2120},[270,15978,15979],{},"    tank_id, bin(time, 1h)\n",[270,15981,15982],{"class":272,"line":2126},[270,15983,4858],{},[270,15985,15986],{"class":272,"line":2132},[270,15987,7699],{},[270,15989,15990],{"class":272,"line":3375},[270,15991,7704],{},[270,15993,15994],{"class":272,"line":3381},[270,15995,15996],{},"  hour_bin,\n",[270,15998,15999],{"class":272,"line":3387},[270,16000,16001],{},"  avg_weight,\n",[270,16003,16004],{"class":272,"line":3393},[270,16005,16006],{},"  avg_weight - LAG(avg_weight) OVER (\n",[270,16008,16009],{"class":272,"line":3399},[270,16010,16011],{},"    PARTITION BY tank_id\n",[270,16013,16014],{"class":272,"line":3405},[270,16015,16016],{},"    ORDER BY hour_bin\n",[270,16018,16019],{"class":272,"line":3411},[270,16020,16021],{},"  ) as fill_rate_per_hour\n",[270,16023,16024],{"class":272,"line":3417},[270,16025,7719],{},[270,16027,16028],{"class":272,"line":3423},[270,16029,16030],{},"  binned_data\n",[270,16032,16033],{"class":272,"line":3429},[270,16034,15849],{},[270,16036,16037],{"class":272,"line":3434},[270,16038,16039],{},"  tank_id, hour_bin DESC\n",[24,16041,16043],{"id":16042},"advanced-analytics","Advanced Analytics",[16,16045,16046],{},[93,16047,16048],{},"4. Anomaly Detection (Statistical):",[29,16050,16052],{"className":1819,"code":16051,"language":1821,"meta":38,"style":38},"WITH stats AS (\n  SELECT\n    tank_id,\n    AVG(measure_value::double) as mean_weight,\n    STDDEV(measure_value::double) as stddev_weight\n  FROM\n    \"FactoryData\".\"TankWeights\"\n  WHERE\n    time BETWEEN ago(7d) AND ago(1d)\n  GROUP BY\n    tank_id\n)\nSELECT\n  t.tank_id,\n  t.time,\n  t.measure_value::double as weight,\n  s.mean_weight,\n  s.stddev_weight,\n  ABS(t.measure_value::double - s.mean_weight) / s.stddev_weight as z_score,\n  CASE\n    WHEN ABS(t.measure_value::double - s.mean_weight) / s.stddev_weight > 3\n    THEN 'ANOMALY'\n    ELSE 'NORMAL'\n  END as status\nFROM\n  \"FactoryData\".\"TankWeights\" t\nJOIN\n  stats s ON t.tank_id = s.tank_id\nWHERE\n  t.time > ago(1h)\nORDER BY\n  z_score DESC\n",[36,16053,16054,16059,16063,16067,16072,16077,16081,16085,16089,16094,16098,16103,16107,16111,16116,16121,16126,16131,16136,16141,16146,16151,16156,16161,16166,16170,16175,16180,16185,16189,16194,16198],{"__ignoreMap":38},[270,16055,16056],{"class":272,"line":273},[270,16057,16058],{},"WITH stats AS (\n",[270,16060,16061],{"class":272,"line":279},[270,16062,15934],{},[270,16064,16065],{"class":272,"line":285},[270,16066,15939],{},[270,16068,16069],{"class":272,"line":291},[270,16070,16071],{},"    AVG(measure_value::double) as mean_weight,\n",[270,16073,16074],{"class":272,"line":297},[270,16075,16076],{},"    STDDEV(measure_value::double) as stddev_weight\n",[270,16078,16079],{"class":272,"line":303},[270,16080,15954],{},[270,16082,16083],{"class":272,"line":515},[270,16084,15959],{},[270,16086,16087],{"class":272,"line":793},[270,16088,15964],{},[270,16090,16091],{"class":272,"line":799},[270,16092,16093],{},"    time BETWEEN ago(7d) AND ago(1d)\n",[270,16095,16096],{"class":272,"line":805},[270,16097,15974],{},[270,16099,16100],{"class":272,"line":2120},[270,16101,16102],{},"    tank_id\n",[270,16104,16105],{"class":272,"line":2126},[270,16106,4858],{},[270,16108,16109],{"class":272,"line":2132},[270,16110,7699],{},[270,16112,16113],{"class":272,"line":3375},[270,16114,16115],{},"  t.tank_id,\n",[270,16117,16118],{"class":272,"line":3381},[270,16119,16120],{},"  t.time,\n",[270,16122,16123],{"class":272,"line":3387},[270,16124,16125],{},"  t.measure_value::double as weight,\n",[270,16127,16128],{"class":272,"line":3393},[270,16129,16130],{},"  s.mean_weight,\n",[270,16132,16133],{"class":272,"line":3399},[270,16134,16135],{},"  s.stddev_weight,\n",[270,16137,16138],{"class":272,"line":3405},[270,16139,16140],{},"  ABS(t.measure_value::double - s.mean_weight) / s.stddev_weight as z_score,\n",[270,16142,16143],{"class":272,"line":3411},[270,16144,16145],{},"  CASE\n",[270,16147,16148],{"class":272,"line":3417},[270,16149,16150],{},"    WHEN ABS(t.measure_value::double - s.mean_weight) / s.stddev_weight > 3\n",[270,16152,16153],{"class":272,"line":3423},[270,16154,16155],{},"    THEN 'ANOMALY'\n",[270,16157,16158],{"class":272,"line":3429},[270,16159,16160],{},"    ELSE 'NORMAL'\n",[270,16162,16163],{"class":272,"line":3434},[270,16164,16165],{},"  END as status\n",[270,16167,16168],{"class":272,"line":3440},[270,16169,7719],{},[270,16171,16172],{"class":272,"line":3446},[270,16173,16174],{},"  \"FactoryData\".\"TankWeights\" t\n",[270,16176,16177],{"class":272,"line":3452},[270,16178,16179],{},"JOIN\n",[270,16181,16182],{"class":272,"line":3457},[270,16183,16184],{},"  stats s ON t.tank_id = s.tank_id\n",[270,16186,16187],{"class":272,"line":3463},[270,16188,7729],{},[270,16190,16191],{"class":272,"line":3469},[270,16192,16193],{},"  t.time > ago(1h)\n",[270,16195,16196],{"class":272,"line":3475},[270,16197,15849],{},[270,16199,16200],{"class":272,"line":3480},[270,16201,16202],{},"  z_score DESC\n",[16,16204,16205],{},[93,16206,16207],{},"5. Data Interpolation (Missing Values):",[29,16209,16211],{"className":1819,"code":16210,"language":1821,"meta":38,"style":38},"SELECT\n  tank_id,\n  INTERPOLATE_LINEAR(\n    CREATE_TIME_SERIES(time, measure_value::double),\n    SEQUENCE(ago(1h), now(), 1m)\n  ) as interpolated_weights\nFROM\n  \"FactoryData\".\"TankWeights\"\nWHERE\n  time > ago(1h)\nGROUP BY\n  tank_id\n",[36,16212,16213,16217,16221,16226,16231,16236,16241,16245,16249,16253,16257,16261],{"__ignoreMap":38},[270,16214,16215],{"class":272,"line":273},[270,16216,7699],{},[270,16218,16219],{"class":272,"line":279},[270,16220,7704],{},[270,16222,16223],{"class":272,"line":285},[270,16224,16225],{},"  INTERPOLATE_LINEAR(\n",[270,16227,16228],{"class":272,"line":291},[270,16229,16230],{},"    CREATE_TIME_SERIES(time, measure_value::double),\n",[270,16232,16233],{"class":272,"line":297},[270,16234,16235],{},"    SEQUENCE(ago(1h), now(), 1m)\n",[270,16237,16238],{"class":272,"line":303},[270,16239,16240],{},"  ) as interpolated_weights\n",[270,16242,16243],{"class":272,"line":515},[270,16244,7719],{},[270,16246,16247],{"class":272,"line":793},[270,16248,15835],{},[270,16250,16251],{"class":272,"line":799},[270,16252,7729],{},[270,16254,16255],{"class":272,"line":805},[270,16256,15899],{},[270,16258,16259],{"class":272,"line":2120},[270,16260,15909],{},[270,16262,16263],{"class":272,"line":2126},[270,16264,15914],{},[11,16266,16268],{"id":16267},"grafana-integration","Grafana Integration",[24,16270,16272],{"id":16271},"add-timestream-data-source","Add Timestream Data Source",[16,16274,16275],{},[93,16276,16277],{},"Grafana Plugin:",[29,16279,16281],{"className":1993,"code":16280,"language":1995,"meta":38,"style":38},"grafana-cli plugins install grafana-timestream-datasource\n",[36,16282,16283],{"__ignoreMap":38},[270,16284,16285,16288,16291,16293],{"class":272,"line":273},[270,16286,16287],{"class":2008},"grafana-cli",[270,16289,16290],{"class":1930}," plugins",[270,16292,2015],{"class":1930},[270,16294,16295],{"class":1930}," grafana-timestream-datasource\n",[16,16297,16298],{},[93,16299,16300],{},"Data Source Configuration:",[29,16302,16304],{"className":3803,"code":16303,"language":3805,"meta":38,"style":38},"{\n  \"name\": \"AWS Timestream\",\n  \"type\": \"grafana-timestream-datasource\",\n  \"access\": \"proxy\",\n  \"jsonData\": {\n    \"defaultRegion\": \"eu-west-1\",\n    \"defaultDatabase\": \"FactoryData\",\n    \"defaultTable\": \"TankWeights\",\n    \"authType\": \"keys\"\n  },\n  \"secureJsonData\": {\n    \"accessKey\": \"AKIA...\",\n    \"secretKey\": \"...\"\n  }\n}\n",[36,16305,16306,16310,16322,16334,16346,16353,16365,16376,16387,16397,16401,16408,16420,16430,16434],{"__ignoreMap":38},[270,16307,16308],{"class":272,"line":273},[270,16309,3812],{"class":1918},[270,16311,16312,16315,16317,16320],{"class":272,"line":279},[270,16313,16314],{"class":2053},"  \"name\"",[270,16316,1927],{"class":1918},[270,16318,16319],{"class":1930},"\"AWS Timestream\"",[270,16321,3825],{"class":1918},[270,16323,16324,16327,16329,16332],{"class":272,"line":285},[270,16325,16326],{"class":2053},"  \"type\"",[270,16328,1927],{"class":1918},[270,16330,16331],{"class":1930},"\"grafana-timestream-datasource\"",[270,16333,3825],{"class":1918},[270,16335,16336,16339,16341,16344],{"class":272,"line":291},[270,16337,16338],{"class":2053},"  \"access\"",[270,16340,1927],{"class":1918},[270,16342,16343],{"class":1930},"\"proxy\"",[270,16345,3825],{"class":1918},[270,16347,16348,16351],{"class":272,"line":297},[270,16349,16350],{"class":2053},"  \"jsonData\"",[270,16352,6468],{"class":1918},[270,16354,16355,16358,16360,16363],{"class":272,"line":303},[270,16356,16357],{"class":2053},"    \"defaultRegion\"",[270,16359,1927],{"class":1918},[270,16361,16362],{"class":1930},"\"eu-west-1\"",[270,16364,3825],{"class":1918},[270,16366,16367,16370,16372,16374],{"class":272,"line":515},[270,16368,16369],{"class":2053},"    \"defaultDatabase\"",[270,16371,1927],{"class":1918},[270,16373,15325],{"class":1930},[270,16375,3825],{"class":1918},[270,16377,16378,16381,16383,16385],{"class":272,"line":793},[270,16379,16380],{"class":2053},"    \"defaultTable\"",[270,16382,1927],{"class":1918},[270,16384,15337],{"class":1930},[270,16386,3825],{"class":1918},[270,16388,16389,16392,16394],{"class":272,"line":799},[270,16390,16391],{"class":2053},"    \"authType\"",[270,16393,1927],{"class":1918},[270,16395,16396],{"class":1930},"\"keys\"\n",[270,16398,16399],{"class":272,"line":805},[270,16400,2098],{"class":1918},[270,16402,16403,16406],{"class":272,"line":2120},[270,16404,16405],{"class":2053},"  \"secureJsonData\"",[270,16407,6468],{"class":1918},[270,16409,16410,16413,16415,16418],{"class":272,"line":2126},[270,16411,16412],{"class":2053},"    \"accessKey\"",[270,16414,1927],{"class":1918},[270,16416,16417],{"class":1930},"\"AKIA...\"",[270,16419,3825],{"class":1918},[270,16421,16422,16425,16427],{"class":272,"line":2132},[270,16423,16424],{"class":2053},"    \"secretKey\"",[270,16426,1927],{"class":1918},[270,16428,16429],{"class":1930},"\"...\"\n",[270,16431,16432],{"class":272,"line":3375},[270,16433,6564],{"class":1918},[270,16435,16436],{"class":272,"line":3381},[270,16437,2129],{"class":1918},[24,16439,16441],{"id":16440},"example-dashboard-query","Example Dashboard Query",[16,16443,16444],{},[93,16445,16446],{},"Panel: Tank Weight Over Time",[29,16448,16450],{"className":1819,"code":16449,"language":1821,"meta":38,"style":38},"SELECT\n  tank_id as metric,\n  time,\n  measure_value::double as weight\nFROM\n  $__database.$__table\nWHERE\n  $__timeFilter\n  AND tank_id IN ($tank_ids)\nORDER BY\n  time\n",[36,16451,16452,16456,16461,16466,16471,16475,16480,16484,16489,16494,16498],{"__ignoreMap":38},[270,16453,16454],{"class":272,"line":273},[270,16455,7699],{},[270,16457,16458],{"class":272,"line":279},[270,16459,16460],{},"  tank_id as metric,\n",[270,16462,16463],{"class":272,"line":285},[270,16464,16465],{},"  time,\n",[270,16467,16468],{"class":272,"line":291},[270,16469,16470],{},"  measure_value::double as weight\n",[270,16472,16473],{"class":272,"line":297},[270,16474,7719],{},[270,16476,16477],{"class":272,"line":303},[270,16478,16479],{},"  $__database.$__table\n",[270,16481,16482],{"class":272,"line":515},[270,16483,7729],{},[270,16485,16486],{"class":272,"line":793},[270,16487,16488],{},"  $__timeFilter\n",[270,16490,16491],{"class":272,"line":799},[270,16492,16493],{},"  AND tank_id IN ($tank_ids)\n",[270,16495,16496],{"class":272,"line":805},[270,16497,15849],{},[270,16499,16500],{"class":272,"line":2120},[270,16501,15826],{},[16,16503,16504],{},[93,16505,16506],{},"Variables:",[40,16508,16509,16515],{},[43,16510,16511,16514],{},[36,16512,16513],{},"$tank_ids",": Multi-select dropdown (1, 2, 3)",[43,16516,16517,16520],{},[36,16518,16519],{},"$__timeFilter",": Grafana auto-generated time filter",[11,16522,4881],{"id":4880},[24,16524,16526],{"id":16525},"pricing-eu-west-1","Pricing (eu-west-1)",[636,16528,16529,16540],{},[639,16530,16531],{},[642,16532,16533,16535,16537],{},[645,16534,11230],{},[645,16536,11233],{},[645,16538,16539],{},"Example Cost",[655,16541,16542,16554,16567,16580],{},[642,16543,16544,16549,16551],{},[660,16545,16546],{},[93,16547,16548],{},"Writes",[660,16550,11287],{},[660,16552,16553],{},"$1.30/day (100K writes/day)",[642,16555,16556,16561,16564],{},[660,16557,16558],{},[93,16559,16560],{},"Memory Store",[660,16562,16563],{},"$0.036 / GB-hour",[660,16565,16566],{},"$0.86/day (1GB, 24h)",[642,16568,16569,16574,16577],{},[660,16570,16571],{},[93,16572,16573],{},"Magnetic Store",[660,16575,16576],{},"$0.03 / GB-month",[660,16578,16579],{},"$30/month (1TB)",[642,16581,16582,16587,16590],{},[660,16583,16584],{},[93,16585,16586],{},"Queries (scanned)",[660,16588,16589],{},"$0.01 / GB scanned",[660,16591,16592],{},"Variable",[24,16594,16596],{"id":16595},"cost-optimization-strategies","Cost Optimization Strategies",[16,16598,16599],{},[93,16600,16601],{},"1. Batch Writes:",[29,16603,16605],{"className":751,"code":16604,"language":753,"meta":38,"style":38},"# ❌ Bad: 1000 individual writes = $0.50\nfor i in range(1000):\n    write_single_record(data[i])\n\n# ✅ Good: 10 batch writes (100 records each) = $0.005\nfor batch in chunks(data, 100):\n    write_batch(batch)\n",[36,16606,16607,16612,16617,16622,16626,16631,16636],{"__ignoreMap":38},[270,16608,16609],{"class":272,"line":273},[270,16610,16611],{},"# ❌ Bad: 1000 individual writes = $0.50\n",[270,16613,16614],{"class":272,"line":279},[270,16615,16616],{},"for i in range(1000):\n",[270,16618,16619],{"class":272,"line":285},[270,16620,16621],{},"    write_single_record(data[i])\n",[270,16623,16624],{"class":272,"line":291},[270,16625,775],{"emptyLinePlaceholder":524},[270,16627,16628],{"class":272,"line":297},[270,16629,16630],{},"# ✅ Good: 10 batch writes (100 records each) = $0.005\n",[270,16632,16633],{"class":272,"line":303},[270,16634,16635],{},"for batch in chunks(data, 100):\n",[270,16637,16638],{"class":272,"line":515},[270,16639,16640],{},"    write_batch(batch)\n",[16,16642,16643],{},[93,16644,16645],{},"2. Shorter Retention:",[29,16647,16649],{"className":1993,"code":16648,"language":1995,"meta":38,"style":38},"# Reduce Memory Store to 12 hours instead of 24\naws timestream-write update-table \\\n  --database-name FactoryData \\\n  --table-name TankWeights \\\n  --retention-properties '{\n    \"MemoryStoreRetentionPeriodInHours\": 12,\n    \"MagneticStoreRetentionPeriodInDays\": 30\n  }'\n",[36,16650,16651,16656,16667,16675,16683,16689,16694,16699],{"__ignoreMap":38},[270,16652,16653],{"class":272,"line":273},[270,16654,16655],{"class":2002},"# Reduce Memory Store to 12 hours instead of 24\n",[270,16657,16658,16660,16662,16665],{"class":272,"line":279},[270,16659,10445],{"class":2008},[270,16661,15163],{"class":1930},[270,16663,16664],{"class":1930}," update-table",[270,16666,10454],{"class":2053},[270,16668,16669,16671,16673],{"class":272,"line":285},[270,16670,15173],{"class":2053},[270,16672,15203],{"class":1930},[270,16674,10454],{"class":2053},[270,16676,16677,16679,16681],{"class":272,"line":291},[270,16678,15210],{"class":2053},[270,16680,15213],{"class":1930},[270,16682,10454],{"class":2053},[270,16684,16685,16687],{"class":272,"line":297},[270,16686,15220],{"class":2053},[270,16688,12530],{"class":1930},[270,16690,16691],{"class":272,"line":303},[270,16692,16693],{"class":1930},"    \"MemoryStoreRetentionPeriodInHours\": 12,\n",[270,16695,16696],{"class":272,"line":515},[270,16697,16698],{"class":1930},"    \"MagneticStoreRetentionPeriodInDays\": 30\n",[270,16700,16701],{"class":272,"line":793},[270,16702,12565],{"class":1930},[16,16704,16705],{},[93,16706,16707],{},"3. Query Optimization:",[29,16709,16711],{"className":1819,"code":16710,"language":1821,"meta":38,"style":38},"-- ❌ Bad: Scans entire table\nSELECT * FROM TankWeights\n\n-- ✅ Good: Limited time range + specific columns\nSELECT tank_id, time, measure_value::double\nFROM TankWeights\nWHERE time > ago(1h)\n  AND measure_name = 'weight'\n",[36,16712,16713,16718,16723,16727,16732,16737,16742,16747],{"__ignoreMap":38},[270,16714,16715],{"class":272,"line":273},[270,16716,16717],{},"-- ❌ Bad: Scans entire table\n",[270,16719,16720],{"class":272,"line":279},[270,16721,16722],{},"SELECT * FROM TankWeights\n",[270,16724,16725],{"class":272,"line":285},[270,16726,775],{"emptyLinePlaceholder":524},[270,16728,16729],{"class":272,"line":291},[270,16730,16731],{},"-- ✅ Good: Limited time range + specific columns\n",[270,16733,16734],{"class":272,"line":297},[270,16735,16736],{},"SELECT tank_id, time, measure_value::double\n",[270,16738,16739],{"class":272,"line":303},[270,16740,16741],{},"FROM TankWeights\n",[270,16743,16744],{"class":272,"line":515},[270,16745,16746],{},"WHERE time > ago(1h)\n",[270,16748,16749],{"class":272,"line":793},[270,16750,15904],{},[24,16752,16754],{"id":16753},"real-world-cost-example","Real-World Cost Example",[16,16756,16757,16759],{},[93,16758,4958],{}," 10 tanks, 1-second polling, 90-day retention",[636,16761,16762,16774],{},[639,16763,16764],{},[642,16765,16766,16769,16771],{},[645,16767,16768],{},"Item",[645,16770,1203],{},[645,16772,16773],{},"Monthly Cost",[655,16775,16776,16788,16800,16812,16825],{},[642,16777,16778,16782,16785],{},[660,16779,16780],{},[93,16781,16548],{},[660,16783,16784],{},"10 devices × 86,400/day × 30 days = 25.9M writes",[660,16786,16787],{},"$12.95",[642,16789,16790,16794,16797],{},[660,16791,16792],{},[93,16793,16560],{},[660,16795,16796],{},"10 devices × 0.1 GB/day × 1 day × $0.036/hour",[660,16798,16799],{},"$0.86",[642,16801,16802,16806,16809],{},[660,16803,16804],{},[93,16805,16573],{},[660,16807,16808],{},"25.9M × 50 bytes = 1.3 GB/month",[660,16810,16811],{},"$0.04",[642,16813,16814,16819,16822],{},[660,16815,16816],{},[93,16817,16818],{},"Queries",[660,16820,16821],{},"~100 GB scanned/month",[660,16823,16824],{},"$1.00",[642,16826,16827,16831,16833],{},[660,16828,16829],{},[93,16830,11310],{},[660,16832],{},[660,16834,16835],{},[93,16836,16837],{},"~$15/month",[16,16839,16840],{},"Compare to self-hosted PostgreSQL: $50-100/month (EC2 + EBS)",[11,16842,444],{"id":443},[16,16844,16845,16847],{},[93,16846,1754],{}," is the ideal solution for storing and analyzing data from industrial sensors:",[16,16849,5091,16850,16853,16854,5098,16856,16859,16860,5098,16862,16865,16866,5098,16868,16870,16871,5098,16873,16876],{},[93,16851,16852],{},"10x faster"," writes than relational databases",[2353,16855],{},[93,16857,16858],{},"90% compression"," (10x cost savings)",[2353,16861],{},[93,16863,16864],{},"Automatic lifecycle management"," (Memory → Magnetic)",[2353,16867],{},[93,16869,15104],{}," (interpolation, binning, windowing)",[2353,16872],{},[93,16874,16875],{},"Grafana integration"," for real-time dashboards",[16,16878,1718,16879,467,16881,16883,16884,16886],{},[463,16880,1360],{"href":1613},[463,16882,2840],{"href":1723}," devices can be easily integrated with Timestream via ",[463,16885,2341],{"href":2340}," for complete cloud-based monitoring.",[24,16888,5132],{"id":5131},[40,16890,16891,16895,16899,16903],{},[43,16892,16893],{},[463,16894,2382],{"href":2340},[43,16896,16897],{},[463,16898,14926],{"href":5197},[43,16900,16901],{},[463,16902,2983],{"href":2634},[43,16904,16905],{},[463,16906,466],{"href":1613},[477,16908,16909],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":38,"searchDepth":279,"depth":279,"links":16911},[16912,16913,16917,16918,16922,16925,16929,16933,16938],{"id":13,"depth":279,"text":14},{"id":15009,"depth":279,"text":15010,"children":16914},[16915,16916],{"id":15019,"depth":285,"text":15020},{"id":15049,"depth":285,"text":15050},{"id":3279,"depth":279,"text":3280},{"id":15141,"depth":279,"text":15142,"children":16919},[16920,16921],{"id":15145,"depth":285,"text":15146},{"id":15258,"depth":285,"text":15259},{"id":15408,"depth":279,"text":15409,"children":16923},[16924],{"id":15412,"depth":285,"text":15413},{"id":15793,"depth":279,"text":15794,"children":16926},[16927,16928],{"id":15797,"depth":285,"text":15798},{"id":16042,"depth":285,"text":16043},{"id":16267,"depth":279,"text":16268,"children":16930},[16931,16932],{"id":16271,"depth":285,"text":16272},{"id":16440,"depth":285,"text":16441},{"id":4880,"depth":279,"text":4881,"children":16934},[16935,16936,16937],{"id":16525,"depth":285,"text":16526},{"id":16595,"depth":285,"text":16596},{"id":16753,"depth":285,"text":16754},{"id":443,"depth":279,"text":444,"children":16939},[16940],{"id":5131,"depth":285,"text":5132},"Efficient storage and analysis of industrial sensor data with AWS Timestream: High-speed writes, automated lifecycle management, and SQL-based analytics.",{"date":3011,"author":514,"readTime":799,"tags":16943},[16944,16945,7985,16946,738,16947],"AWS Timestream","Time Series Database","Data Analytics","SQL",{"title":2377,"description":16941},"en/blog/time-series-data-management-amazon-timestream","TZ1kYsoC8qyX_UWY9E3sJi-F7kznHbXCKdldmoZmzJk",{"id":16952,"title":16953,"body":16954,"description":17043,"extension":511,"meta":17044,"navigation":524,"path":17051,"seo":17052,"stem":17053,"__hash__":17054},"en_blog/en/blog/why-should-you-use-digital-transmitters-in-factories-of-the-future.md","Why Should You Use Digital Transmitters in Factories of the Future?",{"type":8,"value":16955,"toc":17035},[16956,16958,16967,16971,16974,16977,17000,17004,17016,17020,17023,17025,17028],[11,16957,14],{"id":13},[16,16959,16960,16961,16966],{},"Industrial facilities are becoming smarter and more efficient every day with the Industry 4.0 transformation. The cornerstone of this transformation is the sensors and transmitters that carry data from the field to decision-making mechanisms (PLC, SCADA, Cloud). Traditional analog transmitters have served us for years, but let's examine with technical details why you should now use ",[93,16962,16963],{},[463,16964,16965],{"href":1723},"Digital Transmitters"," in the factories of the future.",[11,16968,16970],{"id":16969},"why-should-you-digitalize-analog-vs-digital-comparison","Why Should You Digitalize? Analog vs. Digital Comparison",[16,16972,16973],{},"Analog transmitters (4-20mA, 0-10V) transmit data through the magnitude of electrical signals. This means they have natural limits such as voltage drop on long cables, electromagnetic noise (EMI), and loss of resolution.",[16,16975,16976],{},"Digital transmitters, on the other hand, transmit data in packets (e.g., Modbus RTU/TCP over RS485). Here are the key advantages provided by digital:",[176,16978,16979,16985,16991],{},[43,16980,16981,16984],{},[93,16982,16983],{},"Zero Data Loss",": Since the signal is digitized at the source, the cable distance does not compromise the accuracy of the data.",[43,16986,16987,16990],{},[93,16988,16989],{},"Diagnostics",": They can report not only the measured value but also whether the sensor is disconnected or the device's operating status.",[43,16992,16993,16996,16997,16999],{},[93,16994,16995],{},"Precision",": While analog signals are usually limited to around 12-bit resolution, digital systems offer sensitivity at the ",[93,16998,665],{}," level.",[11,17001,17003],{"id":17002},"the-new-standard-in-precision-measurement-zma-and-gdt-technology","The New Standard in Precision Measurement: ZMA and GDT Technology",[16,17005,17006,17007,467,17011,17015],{},"Factories of the future require millimeter precision and millisecond response times. At Amazeng, we have developed our ",[93,17008,17009],{},[463,17010,471],{"href":1723},[93,17012,17013],{},[463,17014,466],{"href":1613}," platforms to meet this need.",[24,17017,17019],{"id":17018},"full-control-with-gdt-series","Full Control with GDT Series",[16,17021,17022],{},"The GDT Series is not just a transmitter, but also a control center. With its 24-bit resolution and 1000 Hz sampling rate, it doesn't miss the slightest detail when converting analog signals to digital. Thanks to its adaptive filtering algorithms, it cleans out motor noise in the field to provide a pristine data stream.",[11,17024,444],{"id":443},[16,17026,17027],{},"The transition from analog to digital systems is not just a technology update, but a strategic investment for operational efficiency. Lower wiring costs, higher data accuracy, and predictive maintenance opportunities are just a few of the advantages offered by digital transmitters.",[16,17029,17030,17031,17034],{},"To build a more modern and smart measurement infrastructure or to digitalize your existing systems, ",[463,17032,17033],{"href":1628},"contact Amazeng engineers",". Our technical team is ready to design the most suitable project for your facility.",{"title":38,"searchDepth":279,"depth":279,"links":17036},[17037,17038,17039,17042],{"id":13,"depth":279,"text":14},{"id":16969,"depth":279,"text":16970},{"id":17002,"depth":279,"text":17003,"children":17040},[17041],{"id":17018,"depth":285,"text":17019},{"id":443,"depth":279,"text":444},"We examine the differences between analog and digital transmitters in industrial automation, why you should switch to digitalization, and their roles in future factories.",{"date":17045,"author":514,"readTime":303,"tags":17046},"2025-12-19",[17047,17048,10235,17049,17050],"Digital Transmitter","GDT Series","Analog vs Digital","Smart Sensors","/en/blog/why-should-you-use-digital-transmitters-in-factories-of-the-future",{"title":16953,"description":17043},"en/blog/why-should-you-use-digital-transmitters-in-factories-of-the-future","5FZmM_jqE9h_Os8RQoCZoAK36xmcGJ82RIDFE1AGLqw",{"id":17056,"title":17057,"body":17058,"description":17161,"extension":511,"meta":17162,"navigation":524,"path":17167,"seo":17168,"stem":17169,"__hash__":17170},"en_blog/en/blog/gdt-series-end-data-loss-with-modbus-digital-transmitters.md","GDT Series: End Data Loss with Modbus Communicating Digital Transmitters",{"type":8,"value":17059,"toc":17151},[17060,17062,17071,17075,17078,17082,17085,17089,17103,17107,17121,17125,17133,17140,17142,17145],[11,17061,14],{"id":13},[16,17063,17064,17065,17070],{},"In the world of industrial communication, \"Modbus\" has become the de facto standard due to its simplicity and reliability. However, carrying sensitive data collected in the field through this protocol without corruption, delay, and with the highest resolution is not something every transmitter can do. In this article, we examine how the Amazeng ",[93,17066,17067],{},[463,17068,17069],{"href":1723},"GDT Series Digital Transmitters"," end data loss based on Modbus communication.",[11,17072,17074],{"id":17073},"risks-of-traditional-methods","Risks of Traditional Methods",[16,17076,17077],{},"When collecting data with old-style analog transmitters, you are trapped by the resolution of the analog input card on the PLC side. The signal can pick up interference on the way or be misread due to calibration shifts. This leads to unacceptable errors, especially in applications that require high precision like weighing and force measurement.",[11,17079,17081],{"id":17080},"power-of-modbus-with-gdt-series","Power of Modbus with GDT Series",[16,17083,17084],{},"The GDT Series digitizes data with 24-bit resolution while it's still at the sensor tip. Beyond this point, data is no longer a \"current\" or \"voltage,\" but a \"numerical value.\"",[24,17086,17088],{"id":17087},"modbus-rtu-rs485-advantages","Modbus RTU (RS485) Advantages:",[40,17090,17091,17097],{},[43,17092,17093,17096],{},[93,17094,17095],{},"Daisy-Chain",": Connect dozens of GDT devices to the PLC over a single cable, reducing wiring costs.",[43,17098,17099,17102],{},[93,17100,17101],{},"Differential Signal",": Thanks to the RS485 physical layer, it works safely even in motor drive panels under high electromagnetic noise.",[24,17104,17106],{"id":17105},"modbus-tcp-ethernet-advantages","Modbus TCP (Ethernet) Advantages:",[40,17108,17109,17115],{},[43,17110,17111,17114],{},[93,17112,17113],{},"High Speed",": It can connect directly to the network infrastructure for the IT/OT integration of modern factories.",[43,17116,17117,17120],{},[93,17118,17119],{},"Remote Access",": With GDT-TCP models, you can instantly access data at the other end of the factory.",[11,17122,17124],{"id":17123},"product-placement-full-integration-with-gdt-series","Product Placement: Full Integration with GDT Series",[16,17126,17127,17128,17132],{},"The Amazeng ",[93,17129,17130],{},[463,17131,471],{"href":1723}," family adapts to all automation architectures with both Modbus RTU and Modbus TCP options. While observing the data in the field thanks to the 7-segment display on the device, you can simultaneously transfer it to your PLC/SCADA system via Modbus registers.",[16,17134,17135,17136,17139],{},"The device's internal ",[93,17137,17138],{},"digital inputs and outputs (I/O)"," can be controlled via Modbus; this makes it not just a transmitter, but also a distributed I/O module.",[11,17141,444],{"id":443},[16,17143,17144],{},"Data loss in industrial processes means faulty production and downtime. Switching to Modbus-based digital communication ensures your data reaches its destination with 100% accuracy from its source.",[16,17146,17147,17148,472],{},"To access technical documents about our Modbus communicating GDT products or to receive system integration support, you can ",[463,17149,17150],{"href":1628},"fill out our quote request form",{"title":38,"searchDepth":279,"depth":279,"links":17152},[17153,17154,17155,17159,17160],{"id":13,"depth":279,"text":14},{"id":17073,"depth":279,"text":17074},{"id":17080,"depth":279,"text":17081,"children":17156},[17157,17158],{"id":17087,"depth":285,"text":17088},{"id":17105,"depth":285,"text":17106},{"id":17123,"depth":279,"text":17124},{"id":443,"depth":279,"text":444},"Discover how the GDT series digital transmitters, supporting Modbus RTU and TCP protocols, ensure data security in industrial communication.",{"date":17163,"author":514,"readTime":297,"tags":17164},"2025-12-18",[8020,687,17048,17165,17166],"Data Security","Industrial Communication","/en/blog/gdt-series-end-data-loss-with-modbus-digital-transmitters",{"title":17057,"description":17161},"en/blog/gdt-series-end-data-loss-with-modbus-digital-transmitters","q4r8L74Uvp1P52iHgzUPL_7lIo9gh4PUqWyfPiGfUl4",{"id":17172,"title":17173,"body":17174,"description":17452,"extension":511,"meta":17453,"navigation":524,"path":2393,"seo":17457,"stem":17458,"__hash__":17459},"en_blog/en/blog/zma-desk-monitoring-and-datalog-features.md","ZMA-Desk: Real-Time Monitoring and Data Logging Power",{"type":8,"value":17175,"toc":17434},[17176,17179,17183,17189,17194,17196,17241,17245,17248,17262,17265,17269,17275,17281,17284,17335,17339,17362,17366,17370,17373,17377,17380,17384,17387,17391,17394,17398,17415,17418,17420,17423,17426],[16,17177,17178],{},"The ZMA Data Acquisition platform delivers reliable data collection in industrial environments. But the true value of your data lies in how effectively you can manage and analyze it. That's where ZMA-Desk comes in. As a professional desktop application, ZMA-Desk covers everything from live monitoring to data export and analysis.",[11,17180,17182],{"id":17181},"monitoring-see-your-data-in-real-time","Monitoring: See Your Data in Real-Time",[16,17184,17185],{},[17186,17187],"img",{"alt":2442,"src":17188},"/blog/zma-desk-monitoring.webp",[16,17190,17191,17193],{},[93,17192,2442],{}," in ZMA-Desk is designed to track sensor data as it happens.",[24,17195,11453],{"id":11452},[40,17197,17198,17204,17229,17235],{},[43,17199,17200,17203],{},[93,17201,17202],{},"Monitor Up to 4 Channels Live",": Track multiple sensors simultaneously",[43,17205,17206,1919,17209],{},[93,17207,17208],{},"Three Data Display Types",[40,17210,17211,17217,17223],{},[43,17212,17213,17216],{},[93,17214,17215],{},"Raw Value",": Direct sensor output",[43,17218,17219,17222],{},[93,17220,17221],{},"Measured Value",": Calibrated measurement",[43,17224,17225,17228],{},[93,17226,17227],{},"Peak (Max) Value",": Highest value recorded in the selected period",[43,17230,17231,17234],{},[93,17232,17233],{},"Live Charts",": Real-time graphs for each channel",[43,17236,17237,17240],{},[93,17238,17239],{},"Quick Calibration",": One-touch Tare and Zero buttons",[24,17242,17244],{"id":17243},"practical-usage","Practical Usage",[16,17246,17247],{},"Each channel displays independently on the monitoring page. For example:",[40,17249,17250,17253,17256,17259],{},[43,17251,17252],{},"Channel 1: Weight measurement",[43,17254,17255],{},"Channel 2: Pressure reading",[43,17257,17258],{},"Channel 3: Linear Potentiometric Displacement",[43,17260,17261],{},"Channel 4: Flow rate",[16,17263,17264],{},"All monitored simultaneously with real-time graphing. Adjust your zero point with Tare, reset to baseline with Zero.",[11,17266,17268],{"id":17267},"datalog-record-and-export-your-data","Datalog: Record and Export Your Data",[16,17270,17271],{},[17186,17272],{"alt":17273,"src":17274},"Datalog","/blog/zma-desk-datalog.webp",[16,17276,17277,17278,17280],{},"While live monitoring is valuable, capturing and analyzing long-term measurements is often where the real insights emerge. The ",[93,17279,17273],{}," section handles this perfectly.",[24,17282,11453],{"id":17283},"key-features-1",[40,17285,17286,17292,17298,17317,17323,17329],{},[43,17287,17288,17291],{},[93,17289,17290],{},"Selective Channel Recording",": Choose which channels to record",[43,17293,17294,17297],{},[93,17295,17296],{},"Configurable Interval",": Set your measurement period (e.g., 1 second, 5 seconds, 1 minute)",[43,17299,17300,1919,17303],{},[93,17301,17302],{},"Multiple Export Formats",[40,17304,17305,17311],{},[43,17306,17307,17310],{},[93,17308,17309],{},"CSV",": Universal format, opens in any application",[43,17312,17313,17316],{},[93,17314,17315],{},"XLSX",": Excel-compatible, supports formulas and charts",[43,17318,17319,17322],{},[93,17320,17321],{},"Recording Status Indicator",": Know if recording is active",[43,17324,17325,17328],{},[93,17326,17327],{},"Recording Duration Timer",": See how long you've been recording",[43,17330,17331,17334],{},[93,17332,17333],{},"Data Browser",": Navigate and manage recorded files",[24,17336,17338],{"id":17337},"data-analysis-workflow","Data Analysis Workflow",[176,17340,17341,17344,17347,17350,17353,17356,17359],{},[43,17342,17343],{},"Start measurements in Monitoring",[43,17345,17346],{},"Switch to Datalog and select channels to record",[43,17348,17349],{},"Choose CSV or XLSX format",[43,17351,17352],{},"Press Start Recording",[43,17354,17355],{},"Let it run for your desired duration",[43,17357,17358],{},"Stop recording and save to your location",[43,17360,17361],{},"Open in Excel or analysis tool",[11,17363,17365],{"id":17364},"why-zma-desk","Why ZMA-Desk?",[24,17367,17369],{"id":17368},"time-efficiency","Time Efficiency",[16,17371,17372],{},"Automatic recording instead of manual data entry saves hours.",[24,17374,17376],{"id":17375},"long-duration-monitoring","Long-Duration Monitoring",[16,17378,17379],{},"Keep your computer running and collect data for hours or days unattended.",[24,17381,17383],{"id":17382},"easy-sharing","Easy Sharing",[16,17385,17386],{},"CSV/XLSX files open in all standard engineering tools. Colleagues, managers, and customers can instantly view and analyze your data.",[24,17388,17390],{"id":17389},"professional-reporting","Professional Reporting",[16,17392,17393],{},"Create graphs, trend analysis, and detailed reports from recorded data.",[11,17395,17397],{"id":17396},"industrial-applications","Industrial Applications",[16,17399,17400,17402,17403,17406,17407,17410,17411,17414],{},[93,17401,1110],{},": Verify consistency during production\n",[93,17404,17405],{},"Research & Development",": Test sensor performance and system behavior\n",[93,17408,17409],{},"Equipment Monitoring",": Track long-term performance of machinery\n",[93,17412,17413],{},"Compliance Documentation",": Record data for ISO, CE, and other standards",[17416,17417],"hr",{},[11,17419,444],{"id":443},[16,17421,17422],{},"ZMA-Desk transforms the ZMA Data Acquisition platform from a measurement device into a professional data management system. Monitor in real-time to make quick decisions, then use Datalog for comprehensive long-term analysis.",[16,17424,17425],{},"If you need high-precision, reliable data acquisition and management in industrial environments, the ZMA + ZMA-Desk combination is your ideal solution.",[16,17427,17428,17431,17432],{},[93,17429,17430],{},"Learn more about ZMA:"," ",[463,17433,466],{"href":1613},{"title":38,"searchDepth":279,"depth":279,"links":17435},[17436,17440,17444,17450,17451],{"id":17181,"depth":279,"text":17182,"children":17437},[17438,17439],{"id":11452,"depth":285,"text":11453},{"id":17243,"depth":285,"text":17244},{"id":17267,"depth":279,"text":17268,"children":17441},[17442,17443],{"id":17283,"depth":285,"text":11453},{"id":17337,"depth":285,"text":17338},{"id":17364,"depth":279,"text":17365,"children":17445},[17446,17447,17448,17449],{"id":17368,"depth":285,"text":17369},{"id":17375,"depth":285,"text":17376},{"id":17382,"depth":285,"text":17383},{"id":17389,"depth":285,"text":17390},{"id":17396,"depth":279,"text":17397},{"id":443,"depth":279,"text":444},"Discover ZMA-Desk monitoring and datalog features. Live data visualization, real-time charts, and professional data export in CSV/XLSX formats.",{"date":17454,"badge":17455},"2025-12-17",{"label":17456},"Tutorial",{"title":17173,"description":17452},"en/blog/zma-desk-monitoring-and-datalog-features","tQdQzwRmuTglxEwhZj3w0PAuPYpl2HE2Z38ytIJsduU",{"id":17461,"title":17462,"body":17463,"description":17557,"extension":511,"meta":17558,"navigation":524,"path":17561,"seo":17562,"stem":17563,"__hash__":17564},"en_blog/en/blog/the-role-of-industry-4-0-and-digital-transmitters.md","The Role of Industry 4.0 and Digital Transmitters: Smart Sensor Management",{"type":8,"value":17464,"toc":17548},[17465,17467,17475,17479,17482,17502,17506,17509,17513,17520,17524,17531,17535,17538],[11,17466,14],{"id":13},[16,17468,17469,17470,17474],{},"Industry 4.0 is not only making factories automatic, but also transforming them into interconnected and self-deciding smart ecosystems. The smallest but most critical building block of this revolution is the sensors where the data is born. However, for the processing and realization of the raw signal coming from the sensor, ",[93,17471,17472],{},[463,17473,17047],{"href":1723}," technology plays a vital role. In this article, we examine the place of digital transmitters in smart sensor management.",[11,17476,17478],{"id":17477},"what-is-smart-sensor-management","What is Smart Sensor Management?",[16,17480,17481],{},"In traditional systems, a sensor only sends a \"value.\" In the world of Industry 4.0, meta-data such as the sensor's \"health status,\" \"calibration need,\" and \"operating hour\" are also needed. This is where digital transmitters come into play and make passive sensors smart.",[176,17483,17484,17490,17496],{},[43,17485,17486,17489],{},[93,17487,17488],{},"Self-Diagnostics",": Digital transmitters can instantly detect a break or short circuit in the sensor and send an alarm to the PLC.",[43,17491,17492,17495],{},[93,17493,17494],{},"Remote Configuration",": Filter settings or units of all transmitters can be changed through a central system without going to the field.",[43,17497,17498,17501],{},[93,17499,17500],{},"Data Pre-processing (Edge Computing)",": Raw sensor data is filtered and normalized at the transmitter level before being sent to the cloud.",[11,17503,17505],{"id":17504},"heart-of-industry-40-gdt-and-zma-integration","Heart of Industry 4.0: GDT and ZMA Integration",[16,17507,17508],{},"The solutions we offer as Amazeng are designed to be fully compatible with the Industry 4.0 architecture.",[24,17510,17512],{"id":17511},"smart-field-management-with-gdt-series","Smart Field Management with GDT Series",[16,17514,17515,17519],{},[93,17516,17517],{},[463,17518,471],{"href":1723}," makes sensor data part of a digital network with Modbus RTU/TCP support. Thanks to its 3-channel digital I/O structure, it can make local control decisions according to the data from the sensor (e.g., stopping the motor in case of overload); this reduces the central process load.",[24,17521,17523],{"id":17522},"large-scale-data-collection-with-zma","Large-Scale Data Collection with ZMA",[16,17525,17526,17530],{},[93,17527,17528],{},[463,17529,466],{"href":1613}," platform collects data coming from different parts of the factory synchronously with its multi-channel structure. This data provides the cleanest and most reliable fuel for big data analytics and predictive maintenance algorithms.",[11,17532,17534],{"id":17533},"are-you-ready-for-the-future","Are You Ready for the Future?",[16,17536,17537],{},"Industry 4.0 is not just for large-scale factories, but a necessity for every business seeking efficiency. Smart sensor management is the first step in this journey.",[16,17539,17540,17541,8017,17545,472],{},"To learn how you can make the sensors in your facility smart and to examine our Industry 4.0 compatible transmitter solutions, ",[463,17542,17544],{"href":17543},"/en/products","visit our website",[463,17546,17547],{"href":1628},"request support from our technical team",{"title":38,"searchDepth":279,"depth":279,"links":17549},[17550,17551,17552,17556],{"id":13,"depth":279,"text":14},{"id":17477,"depth":279,"text":17478},{"id":17504,"depth":279,"text":17505,"children":17553},[17554,17555],{"id":17511,"depth":285,"text":17512},{"id":17522,"depth":285,"text":17523},{"id":17533,"depth":279,"text":17534},"The critical role of digital transmitters in smart sensor management, data analytics, and predictive maintenance processes in the Industry 4.0 ecosystem.",{"date":17559,"author":514,"readTime":303,"tags":17560},"2025-12-16",[10235,17050,17047,2441,16946],"/en/blog/the-role-of-industry-4-0-and-digital-transmitters",{"title":17462,"description":17557},"en/blog/the-role-of-industry-4-0-and-digital-transmitters","3UisxSbGNi21tw6c3nDYD9kBAa6gbALAMbXcZRk3Q5I",{"id":17566,"title":17567,"body":17568,"description":17707,"extension":511,"meta":17708,"navigation":524,"path":17715,"seo":17716,"stem":17717,"__hash__":17718},"en_blog/en/blog/5-critical-criteria-for-choosing-the-right-transmitter.md","5 Critical Criteria You Should Know for Choosing the Right Transmitter",{"type":8,"value":17569,"toc":17697},[17570,17572,17575,17579,17582,17590,17594,17597,17611,17615,17618,17632,17636,17639,17647,17651,17654,17658,17661,17683,17685,17688],[11,17571,14],{"id":13},[16,17573,17574],{},"The success of an automation system depends on how accurately it reads the physical magnitude (pressure, temperature, load, etc.) in the field. Transmitter selection is at the heart of this reading process. Wrong selection leads to incorrect data, system downtimes, and cost increases. Here are 5 critical criteria you should know to choose the right transmitter.",[11,17576,17578],{"id":17577},"_1-measurement-range-and-resolution","1. Measurement Range and Resolution",[16,17580,17581],{},"The capacity of the transmitter should be slightly above the maximum value you want to measure. However, as the capacity increases, sensitivity at low values may decrease.",[40,17583,17584],{},[43,17585,17586,17589],{},[93,17587,17588],{},"Critical Tip",": Resolution is the smallest change the device can detect. High-quality digital transmitters (24-bit) offer millimeter precision even in wide measurement ranges.",[11,17591,17593],{"id":17592},"_2-output-signal-type","2. Output Signal Type",[16,17595,17596],{},"You must determine the most suitable signal type for your system:",[40,17598,17599,17605],{},[43,17600,17601,17604],{},[93,17602,17603],{},"Analog (4-20mA / 0-10V)",": Suitable for classic PLC systems but can be affected by noise.",[43,17606,17607,17610],{},[93,17608,17609],{},"Digital (Modbus RTU/TCP)",": Prevents data loss, recognizes no distance limits, and carries more information (diagnostic data).",[11,17612,17614],{"id":17613},"_3-operating-environment-conditions","3. Operating Environment Conditions",[16,17616,17617],{},"The environment in which the transmitter will operate determines its durability.",[40,17619,17620,17626],{},[43,17621,17622,17625],{},[93,17623,17624],{},"Protection Class",": IP65/IP67 protection is required for dusty or humid environments.",[43,17627,17628,17631],{},[93,17629,17630],{},"Temperature Range",": Products with low drift (ppm/°C) values should be preferred so that changes in factory internal temperature do not affect the accuracy of the device.",[11,17633,17635],{"id":17634},"_4-filtering-and-response-time","4. Filtering and Response Time",[16,17637,17638],{},"Vibrations in the field (motors, mechanical parts) cause fluctuations in measurement.",[40,17640,17641],{},[43,17642,17643,17646],{},[93,17644,17645],{},"Adaptive Filters",": Smart transmitters must have digital filters that clean noise without distorting the truth.",[11,17648,17650],{"id":17649},"_5-calibration-ease","5. Calibration Ease",[16,17652,17653],{},"Adjusting under field conditions can be difficult. It is a big advantage that \"Zero\" and \"Gain\" adjustments can be made without the need for a computer.",[11,17655,17657],{"id":17656},"solution-amazeng-gdt-and-zma-series","Solution: Amazeng GDT and ZMA Series",[16,17659,17660],{},"Are you having trouble choosing? As Amazeng, we offer a solution for every need:",[40,17662,17663,17673],{},[43,17664,17665,1927,17668,17672],{},[93,17666,17667],{},"Fast and Compact Jobs",[93,17669,17670],{},[463,17671,471],{"href":1723}," offers a plug-and-play solution with its on-screen display and Modbus support.",[43,17674,17675,1927,17678,17682],{},[93,17676,17677],{},"Multi-Channel and Precise Data Collection",[93,17679,17680],{},[463,17681,466],{"href":1613}," is designed for the most demanding test and measurement processes with its 24-bit resolution and 1kHz speed.",[11,17684,444],{"id":443},[16,17686,17687],{},"The right transmitter is the eye of your system. Determining your criteria correctly lowers your maintenance costs and increases your production quality in the long run.",[16,17689,17690,17691,8017,17694,472],{},"Not sure which product is more suitable for your application? ",[463,17692,17693],{"href":17543},"Try our product selection wizard",[463,17695,17696],{"href":1628},"get ideas from our technical team",{"title":38,"searchDepth":279,"depth":279,"links":17698},[17699,17700,17701,17702,17703,17704,17705,17706],{"id":13,"depth":279,"text":14},{"id":17577,"depth":279,"text":17578},{"id":17592,"depth":279,"text":17593},{"id":17613,"depth":279,"text":17614},{"id":17634,"depth":279,"text":17635},{"id":17649,"depth":279,"text":17650},{"id":17656,"depth":279,"text":17657},{"id":443,"depth":279,"text":444},"Technical parameters you should pay attention to when choosing a transmitter to get the best performance in your industrial applications.",{"date":17709,"author":514,"readTime":297,"tags":17710},"2025-12-15",[17711,17712,17713,16995,17714],"Transmitter Selection","Industrial Automation","Sensor","Signal Type","/en/blog/5-critical-criteria-for-choosing-the-right-transmitter",{"title":17567,"description":17707},"en/blog/5-critical-criteria-for-choosing-the-right-transmitter","qO9c7igb2x1kafPKqGhtCkV8Atjhtb-Ee08wiUYvi9Q",{"id":17720,"title":17721,"body":17722,"description":17848,"extension":511,"meta":17849,"navigation":524,"path":17857,"seo":17858,"stem":17859,"__hash__":17860},"en_blog/en/blog/what-are-industrial-transmitter-types.md","Temperature, Pressure, and Level: What are Industrial Transmitter Types?",{"type":8,"value":17723,"toc":17840},[17724,17726,17729,17733,17736,17750,17754,17757,17775,17779,17782,17803,17807,17810,17826,17828,17831],[11,17725,14],{"id":13},[16,17727,17728],{},"Every device that converts the physical world into digital data is a transmitter. However, every physical magnitude has its own unique challenges and measurement techniques. Let's discover the working principles of temperature, pressure, and level transmitters most commonly encountered in factories and why they are critical.",[11,17730,17732],{"id":17731},"_1-temperature-transmitters","1. Temperature Transmitters",[16,17734,17735],{},"Temperature is the most monitored parameter of industrial processes. They usually convert weak signals coming from RTD (Pt100/Pt1000) or Thermocouple sensors into a standard output.",[40,17737,17738,17744],{},[43,17739,17740,17743],{},[93,17741,17742],{},"Application Area",": Ovens, food processing lines, chemical reactors.",[43,17745,17746,17749],{},[93,17747,17748],{},"Why Important?",": If weak mV signals are not converted to 4-20mA or digital data with a transmitter, the measurement error reaches huge dimensions as the cable distance increases.",[11,17751,17753],{"id":17752},"_2-pressure-transmitters","2. Pressure Transmitters",[16,17755,17756],{},"They measure the pressure of liquids or gases and transfer it to the control system.",[40,17758,17759,17764],{},[43,17760,17761,17763],{},[93,17762,17742],{},": Hydraulic systems, compressor lines, vacuum processes.",[43,17765,17766,17769,17770,17774],{},[93,17767,17768],{},"Technical Detail",": The sampling rate of the transmitter (for example, 1000 Hz like the ",[93,17771,17772],{},[463,17773,17048],{"href":1723},") is of critical importance to capture high-speed changes.",[11,17776,17778],{"id":17777},"_3-level-transmitters","3. Level Transmitters",[16,17780,17781],{},"They are used to measure the amount of liquid or solid materials in tanks.",[40,17783,17784,17790],{},[43,17785,17786,17789],{},[93,17787,17788],{},"Types",": Ultrasonic (non-contact), hydrostatic (pressure-based), or level measurement with loadcell-based weighing.",[43,17791,17792,17795,17796,17802],{},[93,17793,17794],{},"Product Placement",": In hygienic applications such as milk tanks, load cells placed under the tank and the ",[93,17797,17798],{},[463,17799,17801],{"href":17800},"/en/products/milk-tank-control-unit","Milk Tank Control Unit"," processing this data provide the most precise level information.",[11,17804,17806],{"id":17805},"common-denominator-of-transmitters-signal-conversion","Common Denominator of Transmitters: Signal Conversion",[16,17808,17809],{},"Whether you measure temperature or pressure, a unity of \"language\" is needed for all this data to reach PLC or SCADA. This is where Amazeng's universal data collection solutions come into play.",[40,17811,17812,17819],{},[43,17813,17814,17818],{},[93,17815,17816],{},[463,17817,471],{"href":1723},": It is not bound to only one type of sensor; it accepts 4-20mA, 0-10V, or mV/V (loadcell/pressure) signals and converts them into smart Modbus data.",[43,17820,17821,17825],{},[93,17822,17823],{},[463,17824,466],{"href":1613},": It allows you to collect data from all these different transmitter types in your factory in a single center with 24-bit resolution.",[11,17827,444],{"id":443},[16,17829,17830],{},"Industrial transmitters are the invisible heroes of modern production. Choosing the right type and a high-quality data collection interface for every process ensures the longevity of your system.",[16,17832,17833,17834,8017,17837,472],{},"To discover which transmitter type is suitable for your project, ",[463,17835,17836],{"href":17543},"examine our product page",[463,17838,17839],{"href":1628},"leave us a message",{"title":38,"searchDepth":279,"depth":279,"links":17841},[17842,17843,17844,17845,17846,17847],{"id":13,"depth":279,"text":14},{"id":17731,"depth":279,"text":17732},{"id":17752,"depth":279,"text":17753},{"id":17777,"depth":279,"text":17778},{"id":17805,"depth":279,"text":17806},{"id":443,"depth":279,"text":444},"A comprehensive guide to the most commonly used transmitter types in industry, their functions, and application areas.",{"date":17850,"author":514,"readTime":303,"tags":17851},"2025-12-14",[17852,17853,17854,17855,17856],"Transmitter Types","Temperature Transmitter","Pressure Transmitter","Level Measurement","Industrial Instrumentation","/en/blog/what-are-industrial-transmitter-types",{"title":17721,"description":17848},"en/blog/what-are-industrial-transmitter-types","duxo3tvM9B3EU9EWvB3iVgMAtiYsfH643WehDjqhrS8",{"id":17862,"title":17863,"body":17864,"description":17965,"extension":511,"meta":17966,"navigation":524,"path":17977,"seo":17978,"stem":17979,"__hash__":17980},"en_blog/en/blog/zma-joins-zephyr-project-portfolio.md","ZMA Data Acquisition Joins Zephyr Project Portfolio!",{"type":8,"value":17865,"toc":17959},[17866,17877,17881,17884,17888,17891,17919,17923,17926,17929,17933,17936,17939,17941,17948],[16,17867,17868,17869,17872,17873,17876],{},"We're thrilled to share some exciting news: Our ZMA Data Acquisition product has been accepted into the ",[93,17870,17871],{},"Zephyr Project's official portfolio","! This is particularly special for us as it marks the ",[93,17874,17875],{},"first product from Turkey"," to be featured in this prestigious list.",[11,17878,17880],{"id":17879},"what-is-zephyr-project","What is Zephyr Project?",[16,17882,17883],{},"Zephyr is an open-source real-time operating system (RTOS) developed under the Linux Foundation. It's used across a wide range of applications, from microcontrollers to IoT devices, embedded systems to industrial automation products. World-leading brands like Framework Laptop, Google Chromebook, and Vestas wind turbines run on Zephyr.",[11,17885,17887],{"id":17886},"zmas-journey-with-zephyr","ZMA's Journey with Zephyr",[16,17889,17890],{},"When developing ZMA Data Acquisition, we were searching for a reliable, scalable platform that meets industrial standards. Zephyr RTOS provided us with the flexibility and robustness we needed:",[40,17892,17893,17900,17907,17913],{},[43,17894,17895,17896,17899],{},"Easy dependency management with ",[93,17897,17898],{},"West Workspace"," system",[43,17901,17902,17903,17906],{},"Seamless hardware integration with ",[93,17904,17905],{},"custom board support"," (zma_v1 and zma_v2)",[43,17908,17909,17910],{},"Secure firmware updates via ",[93,17911,17912],{},"MCUboot",[43,17914,17915,17916],{},"Efficient peripheral usage (GPIO, ADC, SPI, UART) through ",[93,17917,17918],{},"modular driver architecture",[11,17920,17922],{"id":17921},"why-this-matters","Why This Matters",[16,17924,17925],{},"The Zephyr Project portfolio isn't just a list; it's the go-to reference for the global embedded systems community. Being listed alongside giants like Google, Vestas, and Framework demonstrates ZMA's technical quality and compliance with global standards.",[16,17927,17928],{},"Being the first product from Turkey proves once again how valuable Turkish engineering talent is on international platforms.",[11,17930,17932],{"id":17931},"whats-next","What's Next",[16,17934,17935],{},"This achievement marks a new beginning for us. We'll continue to enhance ZMA, contribute to the Zephyr community, and inspire more open-source projects from Turkey to the world.",[16,17937,17938],{},"We thank the entire Zephyr Project community for their contributions. Together, we'll keep creating innovative solutions!",[17416,17940],{},[16,17942,17943,17431,17945],{},[93,17944,17430],{},[463,17946,17947],{"href":1613},"ZMA Data Acquisition Product Page",[16,17949,17950,17431,17953],{},[93,17951,17952],{},"ZMA on Zephyr Project:",[463,17954,17958],{"href":17955,"rel":17956},"https://www.zephyrproject.org/portfolio/zma-data-acquisition/",[17957],"nofollow","ZMA on Zephyr Portfolio",{"title":38,"searchDepth":279,"depth":279,"links":17960},[17961,17962,17963,17964],{"id":17879,"depth":279,"text":17880},{"id":17886,"depth":279,"text":17887},{"id":17921,"depth":279,"text":17922},{"id":17931,"depth":279,"text":17932},"ZMA becomes the first product from Turkey to be featured in the Zephyr Project portfolio, joining the global embedded systems community.",{"image":17967,"authors":17969,"date":17850,"featured":524,"badge":17975},{"src":17968},"/products/zma/zma-front.png",[17970],{"name":17971,"to":17972,"avatar":17973},"Amazeng Team","https://amazeng.com.tr/en",{"src":17974},"/apple-touch-icon.png",{"label":17976},"Announcement","/en/blog/zma-joins-zephyr-project-portfolio",{"title":17863,"description":17965},"en/blog/zma-joins-zephyr-project-portfolio","ySOKLvwLGUsI-KZM9-iH2QlWQS9ZfXraFYff04nKQ2A",{"id":17982,"title":17983,"body":17984,"description":18126,"extension":511,"meta":18127,"navigation":524,"path":18135,"seo":18136,"stem":18137,"__hash__":18138},"en_blog/en/blog/how-to-prevent-noise-in-transmitter-signals.md","How to Prevent Noise in Transmitter Signals?",{"type":8,"value":17985,"toc":18114},[17986,17988,17991,17995,17998,18018,18022,18026,18029,18033,18036,18040,18049,18053,18056,18069,18073,18085,18088,18103,18105,18108],[11,17987,14],{"id":13},[16,17989,17990],{},"Industrial fields are a complete \"electrical noise\" field due to motor drives (VFD), contactors, and high voltage lines. Micro-volt level signals coming from a sensitive sensor can easily get lost or corrupted within this noise. So, how to prevent noise in transmitter signals? We examine the golden rules you need to apply for a stable and reliable measurement.",[11,17992,17994],{"id":17993},"recognizing-noise-sources","Recognizing Noise Sources",[16,17996,17997],{},"The first step to preventing noise is to understand where it comes from:",[40,17999,18000,18006,18012],{},[43,18001,18002,18005],{},[93,18003,18004],{},"Electromagnetic Interference (EMI)",": Caused by radio waves and high voltage lines.",[43,18007,18008,18011],{},[93,18009,18010],{},"Radio Frequency Interference (RFI)",": Caused by radio devices and wireless communication systems.",[43,18013,18014,18017],{},[93,18015,18016],{},"Ground Loops",": Formed from ground potential differences at different points.",[11,18019,18021],{"id":18020},"_5-ways-to-increase-signal-quality","5 Ways to Increase Signal Quality",[24,18023,18025],{"id":18024},"_1-using-shielded-cables","1. Using Shielded Cables",[16,18027,18028],{},"Your signal cables must be shielded and this shield must be grounded from only a single point (usually from the ground on the panel side). Double-sided grounding can cause \"ground loop\" noise.",[24,18030,18032],{"id":18031},"_2-physical-separation","2. Physical Separation",[16,18034,18035],{},"Never run signal cables through the same channel as power cables (motor, supply, etc.). If they must cross, cross them at a 90-degree angle.",[24,18037,18039],{"id":18038},"_3-using-differential-signals","3. Using Differential Signals",[16,18041,18042,18043,18048],{},"Differential communication layers like RS485 are designed to cancel out the noise on the line. Therefore, ",[93,18044,18045],{},[463,18046,18047],{"href":1723},"Modbus communicating transmitters"," are much more resistant than analog systems.",[24,18050,18052],{"id":18051},"_4-digital-filtering","4. Digital Filtering",[16,18054,18055],{},"Software filters are used to clean noise from data that cannot be physically prevented.",[40,18057,18058,18064],{},[43,18059,18060,18063],{},[93,18061,18062],{},"Moving Average",": Softens sudden jumps in the signal.",[43,18065,18066,18068],{},[93,18067,17645],{},": Suppresses only noise by learning the character of the signal.",[11,18070,18072],{"id":18071},"amazeng-solution-adaptive-filter-technology","Amazeng Solution: Adaptive Filter Technology",[16,18074,18075,18076,467,18080,18084],{},"The ",[93,18077,18078],{},[463,18079,471],{"href":1723},[93,18081,18082],{},[463,18083,466],{"href":1613}," devices developed by Amazeng engineers are best in class in fighting noise.",[16,18086,18087],{},"Adaptive Digital Filter technology found in our devices:",[40,18089,18090,18093,18096],{},[43,18091,18092],{},"Cleans high-frequency noises without reducing measurement speed.",[43,18094,18095],{},"Offers the user the opportunity to instantly adjust the hardness of the filter in the field.",[43,18097,18098,18099,18102],{},"Allows you to analyze the character of noise visually via ",[93,18100,18101],{},"ZMA-Desk"," software.",[11,18104,444],{"id":443},[16,18106,18107],{},"Fighting noise is a combination of choosing the right hardware and correct mounting techniques. A noise-free data flow prevents your system from getting \"confused\" and prevents faulty alarms/downtimes.",[16,18109,18110,18113],{},[463,18111,18112],{"href":1628},"Contact our engineers"," to solve the noise problems in your facility and to try our products with high noise immunity.",{"title":38,"searchDepth":279,"depth":279,"links":18115},[18116,18117,18118,18124,18125],{"id":13,"depth":279,"text":14},{"id":17993,"depth":279,"text":17994},{"id":18020,"depth":279,"text":18021,"children":18119},[18120,18121,18122,18123],{"id":18024,"depth":285,"text":18025},{"id":18031,"depth":285,"text":18032},{"id":18038,"depth":285,"text":18039},{"id":18051,"depth":285,"text":18052},{"id":18071,"depth":279,"text":18072},{"id":443,"depth":279,"text":444},"Technical tips and solution methods to minimize the effect of electrical noise in industrial environments on transmitter signals.",{"date":18128,"author":514,"readTime":515,"tags":18129},"2025-12-13",[18130,18131,18132,18133,18134],"Noise Prevention","Noise Reduction","Transmitter","Signal Quality","Industrial Interference","/en/blog/how-to-prevent-noise-in-transmitter-signals",{"title":17983,"description":18126},"en/blog/how-to-prevent-noise-in-transmitter-signals","G6KMX0LABk0w1fsaPkMi8eDHoGGmwDWKD-oVIdOuWHU",{"id":18140,"title":18141,"body":18142,"description":18333,"extension":511,"meta":18334,"navigation":524,"path":18339,"seo":18340,"stem":18341,"__hash__":18342},"en_blog/en/blog/4-20ma-or-0-10v-comparison-of-transmitter-output-signals.md","4-20mA or 0-10V? Comparison of Transmitter Output Signals",{"type":8,"value":18143,"toc":18320},[18144,18146,18149,18153,18156,18158,18178,18182,18185,18187,18207,18210,18218,18220,18278,18282,18285,18301,18303,18314],[11,18145,14],{"id":13},[16,18147,18148],{},"In the analog world, communication between transmitters and PLCs takes place basically in two languages: Current (4-20mA) or Voltage (0-10V/0-5V). Both signal types have their own strengths and weak points. So, which one should you choose for your project? In this article, we compare the 4-20mA and 0-10V worlds technically.",[11,18150,18152],{"id":18151},"_4-20ma-the-industry-standard","4-20mA: The Industry Standard",[16,18154,18155],{},"The 4-20mA current loop is the most preferred signal type in industrial environments.",[24,18157,95],{"id":214},[40,18159,18160,18166,18172],{},[43,18161,18162,18165],{},[93,18163,18164],{},"Noise Immunity",": The current signal is affected by electromagnetic interference (EMI) in the environment much less than the voltage signal.",[43,18167,18168,18171],{},[93,18169,18170],{},"Cable Break Detection",": Since the signal base is 4mA, when the value drops to 0mA, the system immediately understands that the cable is broken.",[43,18173,18174,18177],{},[93,18175,18176],{},"Distance",": Losses caused by line resistance in long cable distances do not change the current, which preserves the accuracy of the data.",[11,18179,18181],{"id":18180},"_0-10v-simple-and-economical","0-10V: Simple and Economical",[16,18183,18184],{},"Voltage signals are generally preferred in shorter distance and less noisy environments.",[24,18186,95],{"id":2604},[40,18188,18189,18195,18201],{},[43,18190,18191,18194],{},[93,18192,18193],{},"Easy Measurement",": It is very easy to check the signal with a multimeter.",[43,18196,18197,18200],{},[93,18198,18199],{},"Low Power Consumption",": It consumes less energy than a current loop.",[43,18202,18203,18206],{},[93,18204,18205],{},"Compatibility",": Many hobby electronics and simple automation devices have a direct 0-10V input.",[24,18208,111],{"id":18209},"disadvantages",[40,18211,18212,18215],{},[43,18213,18214],{},"Data is transmitted incorrectly on long cables due to voltage drop.",[43,18216,18217],{},"0V can mean both \"zero value\" and \"cable broken,\" which makes diagnostic difficult.",[11,18219,2663],{"id":2662},[636,18221,18222,18235],{},[639,18223,18224],{},[642,18225,18226,18229,18232],{},[645,18227,647],{"align":18228},"left",[645,18230,18231],{"align":18228},"4-20 mA",[645,18233,18234],{"align":18228},"0-10 V",[655,18236,18237,18248,18259,18269],{},[642,18238,18239,18242,18245],{},[660,18240,18241],{"align":18228},"Noise Resistance",[660,18243,18244],{"align":18228},"Very High",[660,18246,18247],{"align":18228},"Low",[642,18249,18250,18253,18256],{},[660,18251,18252],{"align":18228},"Transmission Distance",[660,18254,18255],{"align":18228},"Long (>1000m)",[660,18257,18258],{"align":18228},"Short (\u003C10m)",[642,18260,18261,18263,18266],{},[660,18262,16989],{"align":18228},[660,18264,18265],{"align":18228},"Cable break recognized",[660,18267,18268],{"align":18228},"Not recognized",[642,18270,18271,18273,18276],{},[660,18272,2217],{"align":18228},[660,18274,18275],{"align":18228},"Medium",[660,18277,18247],{"align":18228},[11,18279,18281],{"id":18280},"master-both-worlds-with-amazeng","Master Both Worlds with Amazeng",[16,18283,18284],{},"Whatever your application, Amazeng solutions support both signal types:",[40,18286,18287,18294],{},[43,18288,18289,18293],{},[93,18290,18291],{},[463,18292,471],{"href":1723},": Accepts both 4-20mA and 0-10V inputs as factory default and combines the best features of both worlds by converting them to digital Modbus data.",[43,18295,18296,18300],{},[93,18297,18298],{},[463,18299,466],{"href":1613},": With its multi-channel structure, it can read 4-20mA from one channel and 0-10V from the other, collecting all data on a single screen.",[11,18302,444],{"id":443},[16,18304,18305,18306,18309,18310,18313],{},"The rule is simple: If the distance is long and there are noise sources such as motor drives in the environment, ",[93,18307,18308],{},"4-20mA","; if the distance is very short and the budget is limited, ",[93,18311,18312],{},"0-10V"," can be preferred. However, if you want to completely secure your data, converting these analog signals to digital with a transmitter is the most guaranteed way.",[16,18315,18316,18319],{},[463,18317,18318],{"href":1628},"Consult our technical team"," for technical questions and our signal conversion solutions.",{"title":38,"searchDepth":279,"depth":279,"links":18321},[18322,18323,18326,18330,18331,18332],{"id":13,"depth":279,"text":14},{"id":18151,"depth":279,"text":18152,"children":18324},[18325],{"id":214,"depth":285,"text":95},{"id":18180,"depth":279,"text":18181,"children":18327},[18328,18329],{"id":2604,"depth":285,"text":95},{"id":18209,"depth":285,"text":111},{"id":2662,"depth":279,"text":2663},{"id":18280,"depth":279,"text":18281},{"id":443,"depth":279,"text":444},"Differences, advantages, and correct selection criteria between 4-20mA and 0-10V, the most commonly used analog output signals in industrial transmitters.",{"date":18335,"author":514,"readTime":303,"tags":18336},"2025-12-12",[18308,18312,18337,18338,17712],"Analog Signal","Transmitter Output","/en/blog/4-20ma-or-0-10v-comparison-of-transmitter-output-signals",{"title":18141,"description":18333},"en/blog/4-20ma-or-0-10v-comparison-of-transmitter-output-signals","GZ-Jm1QLRBFxPs_2ymKbWjxzhpRGuNhL32G2TbuJihU",{"id":18344,"title":18345,"body":18346,"description":18555,"extension":511,"meta":18556,"navigation":524,"path":6115,"seo":18560,"stem":18561,"__hash__":18562},"en_blog/en/blog/why-we-use-zephyr-rtos.md","Why We Use Zephyr RTOS in Our Products",{"type":8,"value":18347,"toc":18546},[18348,18350,18361,18364,18368,18379,18382,18405,18408,18412,18423,18426,18444,18448,18451,18454,18480,18484,18490,18508,18512,18515,18535,18537,18540],[11,18349,14],{"id":13},[16,18351,18352,18353,18360],{},"When designing our industrial data acquisition (DAQ) devices, we focused not only on hardware capability but also on software reliability and sustainability. We want to share the reasons behind choosing ",[93,18354,18355],{},[463,18356,18359],{"href":18357,"rel":18358},"https://www.zephyrproject.org/",[17957],"Zephyr RTOS"," as the operating system for our ZMA series products and the advantages this choice enables.",[16,18362,18363],{},"The key factors that led us to this modern Real-Time Operating System (RTOS) were security, modularity, and compliance with industrial standards.",[11,18365,18367],{"id":18366},"streamlined-development-with-t2-workspace-topology","Streamlined Development with T2 Workspace Topology",[16,18369,18370,18371,18374,18375,18378],{},"One of Zephyr's greatest strengths is how it manages complex dependencies. In our projects, we utilize the \"T2 Workspace\" topology pattern. Thanks to the ",[36,18372,18373],{},"west"," tool and the ",[36,18376,18377],{},"west.yml"," manifest file, we manage all project requirements from a central point.",[16,18380,18381],{},"Instead of importing the entire Zephyr codebase, we selectively import only the modules we need:",[40,18383,18384,18393,18399],{},[43,18385,18386,467,18389,18392],{},[93,18387,18388],{},"cmsis_6",[93,18390,18391],{},"hal_stm32",": For processor architecture and hardware abstraction layers.",[43,18394,18395,18398],{},[93,18396,18397],{},"mcuboot",": For the secure bootloader.",[43,18400,18401,18404],{},[93,18402,18403],{},"mbedtls",": For cryptographic operations and security.",[16,18406,18407],{},"This approach keeps our codebase clean and allows for controlled updates.",[11,18409,18411],{"id":18410},"custom-board-support","Custom Board Support",[16,18413,18414,18415,18418,18419,18422],{},"Our ZMA data acquisition devices (v1 and v2) feature custom-designed STM32-based boards. Zephyr's flexible \"Device Tree\" structure allows us to easily create ",[36,18416,18417],{},".dts"," files and ",[36,18420,18421],{},"Kconfig"," configurations specific to our hardware.",[16,18424,18425],{},"This structure provides us with:",[176,18427,18428,18434],{},[43,18429,18430,18433],{},[93,18431,18432],{},"Hardware Abstraction",": We can switch between hardware revisions without changing the core logic of our code.",[43,18435,18436,18439,18440,18443],{},[93,18437,18438],{},"Rapid Prototyping",": We can test the exact same code on standard development boards like ",[36,18441,18442],{},"Nucleo"," using overlay files.",[11,18445,18447],{"id":18446},"robust-driver-infrastructure","Robust Driver Infrastructure",[16,18449,18450],{},"Instead of writing drivers at the register level one by one, we leverage Zephyr's rich subsystem and driver support. This allows us to abstract hardware complexity and focus on our primary task: data processing.",[16,18452,18453],{},"Key driver advantages we utilize include:",[40,18455,18456,18462,18468,18474],{},[43,18457,18458,18461],{},[93,18459,18460],{},"GPIO & PWM",": Precise control for system status LEDs and alert mechanisms.",[43,18463,18464,18467],{},[93,18465,18466],{},"ADC Integration",": We use Zephyr's standard ADC API to communicate with high-precision external ADC sensors via SPI. This ensures our upper-layer software remains unchanged even if the sensor model changes.",[43,18469,18470,18473],{},[93,18471,18472],{},"UART & Console",": A robust serial communication infrastructure for logging and Modbus RTU.",[43,18475,18476,18479],{},[93,18477,18478],{},"EEPROM",": Standardized storage drivers for securely saving device configurations in non-volatile memory.",[11,18481,18483],{"id":18482},"security-and-mcuboot","Security and MCUboot",[16,18485,18486,18487,18489],{},"Security is not an option in industrial devices; it is a necessity. As part of the Zephyr ecosystem, we integrated ",[93,18488,17912],{}," to provide \"Secure Boot\" capabilities to our devices.",[40,18491,18492,18502],{},[43,18493,18494,18497,18498,18501],{},[93,18495,18496],{},"Signature Verification",": Our devices only run software that has been signed and verified by us using an ",[93,18499,18500],{},"RSA-2048"," key.",[43,18503,18504,18507],{},[93,18505,18506],{},"Secure Updates",": It offers a resilient structure against errors that might occur during software updates.",[11,18509,18511],{"id":18510},"quality-and-standards","Quality and Standards",[16,18513,18514],{},"Another reason for choosing Zephyr is the quality assurance it provides:",[40,18516,18517,18523,18529],{},[43,18518,18519,18522],{},[93,18520,18521],{},"Built-in Tools",": A powerful toolset for debugging and analysis.",[43,18524,18525,18528],{},[93,18526,18527],{},"Hardening Tools",": Tools that take proactive measures against security vulnerabilities.",[43,18530,18531,18534],{},[93,18532,18533],{},"MISRA Compliance",": Adherence to industrial coding standards that enhance code quality and safety.",[11,18536,444],{"id":443},[16,18538,18539],{},"Zephyr RTOS offers the ZMA product family more than just an operating system; it provides a modern, secure, and sustainable development ecosystem. This translates into more stable, secure, and long-lasting products for our customers. The future of the industry lies in open-source, secure, and modular structures, and we are ready for this future with Zephyr.",[16,18541,18542,18543,18545],{},"Visit our product page to explore the ",[463,18544,466],{"href":1613}," device powered by Zephyr RTOS.",{"title":38,"searchDepth":279,"depth":279,"links":18547},[18548,18549,18550,18551,18552,18553,18554],{"id":13,"depth":279,"text":14},{"id":18366,"depth":279,"text":18367},{"id":18410,"depth":279,"text":18411},{"id":18446,"depth":279,"text":18447},{"id":18482,"depth":279,"text":18483},{"id":18510,"depth":279,"text":18511},{"id":443,"depth":279,"text":444},"Explaining our choice of Zephyr RTOS for ZMA Data Acquisition devices, highlighting T2 Workspace topology, custom board support, and secure boot advantages.",{"date":18335,"author":514,"readTime":297,"tags":18557},[18359,1645,2441,18558,18559],"Data Acquisition","Secure Boot",{"title":18345,"description":18555},"en/blog/why-we-use-zephyr-rtos","J9rOxOck8PHdPDIdWZZ8z6c5irsmMa-uEt66OVCA5jM",{"id":18564,"title":18565,"body":18566,"description":18713,"extension":511,"meta":18714,"navigation":524,"path":18719,"seo":18720,"stem":18721,"__hash__":18722},"en_blog/en/blog/which-sensor-gives-which-output.md","Which Sensor Gives Which Output? The World of 4-20mA, 0-10V, and mV/V",{"type":8,"value":18567,"toc":18705},[18568,18570,18573,18577,18584,18604,18608,18611,18623,18627,18630,18642,18646,18649,18688,18690,18699],[11,18569,14],{"id":13},[16,18571,18572],{},"When you buy an industrial sensor, you see expressions like \"Output: 4-20mA\" or \"Output: 2mV/V\" in its catalog. So why do these differences exist? Why does which sensor type prefer a specific output signal? In this article, we take a closer look at the signal variety in the sensor world and their application areas.",[11,18574,18576],{"id":18575},"_1-mvv-ratiometric-output-the-basis-of-precision","1. mV/V (Ratiometric) Output: The Basis of Precision",[16,18578,18579,18580,18583],{},"Usually seen in ",[93,18581,18582],{},"Loadcells"," and some sensitive pressure sensors.",[40,18585,18586,18592,18598],{},[43,18587,18588,18591],{},[93,18589,18590],{},"Why is it used?",": These sensors have a Wheatstone bridge structure. They produce a very small voltage relative to the supply voltage.",[43,18593,18594,18597],{},[93,18595,18596],{},"Example",": A 2mV/V sensor working with 10V supply gives only 20mV (0.02 Volt) output at maximum load.",[43,18599,18600,18603],{},[93,18601,18602],{},"Challenge",": To process such a small signal, a very high-resolution (24-bit) transmitter is needed.",[11,18605,18607],{"id":18606},"_2-4-20ma-current-output-indispensable-of-the-sector","2. 4-20mA Current Output: Indispensable of the Sector",[16,18609,18610],{},"It is the most common type in temperature transmitters, level sensors, and general industrial instruments.",[40,18612,18613,18618],{},[43,18614,18615,18617],{},[93,18616,18590],{},": It does not cause data loss at long distances (up to 1 km) and is very resistant to noise.",[43,18619,18620,18622],{},[93,18621,18596],{},": A pressure transmitter sends 4mA at 0 Bar and 20mA at 10 Bar.",[11,18624,18626],{"id":18625},"_3-0-10v-0-5v-voltage-output-simple-and-local","3. 0-10V / 0-5V Voltage Output: Simple and Local",[16,18628,18629],{},"It often appears in short-distance applications and building automation.",[40,18631,18632,18637],{},[43,18633,18634,18636],{},[93,18635,18590],{},": Can be directly connected to analog inputs of PLCs, does not require an additional resistor.",[43,18638,18639,18641],{},[93,18640,18596],{},": A humidity sensor produced 0V output at 0% humidity and 10V output at 100% humidity.",[11,18643,18645],{"id":18644},"which-transmitter-for-which-output","Which Transmitter for Which Output?",[16,18647,18648],{},"Amazeng's flexible transmitter family is by your side to translate different languages of different sensors into a common language (Modbus or digital screen):",[40,18650,18651,18677],{},[43,18652,18653,1015,18657],{},[93,18654,18655],{},[463,18656,471],{"href":1723},[40,18658,18659,18665,18671],{},[43,18660,18661,18664],{},[93,18662,18663],{},"mV/V Support",": Faultlessly processes micro-volt level data coming from loadcells.",[43,18666,18667,18670],{},[93,18668,18669],{},"Internal Supply",": Provides the 10V/5V voltage needed to supply the sensor through itself.",[43,18672,18673,18676],{},[93,18674,18675],{},"Flexibility",": You can change the input type to 4-20mA or 0-10V in seconds via the menu.",[43,18678,18679,1015,18683],{},[93,18680,18681],{},[463,18682,466],{"href":1613},[40,18684,18685],{},[43,18686,18687],{},"Offers a hybrid channel structure capable of reading both loadcell (mV/V) and analog (4-20mA) sensors at the same time.",[11,18689,444],{"id":443},[16,18691,18692,18693,18695,18696,18698],{},"The sensor output type determines the architecture of your system. ",[93,18694,8127],{}," ratiometric signals offer the highest precision, while ",[93,18697,18308],{}," provides the most reliable transmission. Amazeng transmitters eliminate this signal mess and offer you clean and easy-to-process digital data.",[16,18700,18701,18702,472],{},"Do you need help choosing the transmitter suitable for your sensor's output type? ",[463,18703,18704],{"href":1628},"Our technical team is ready to guide you",{"title":38,"searchDepth":279,"depth":279,"links":18706},[18707,18708,18709,18710,18711,18712],{"id":13,"depth":279,"text":14},{"id":18575,"depth":279,"text":18576},{"id":18606,"depth":279,"text":18607},{"id":18625,"depth":279,"text":18626},{"id":18644,"depth":279,"text":18645},{"id":443,"depth":279,"text":444},"We technically explain the analog signal types produced by pressure, temperature, and weight sensors and why these signals vary.",{"date":18715,"author":514,"readTime":303,"tags":18716},"2025-12-11",[18717,8127,18308,10217,18718],"Sensor Outputs","Pressure Sensor","/en/blog/which-sensor-gives-which-output",{"title":18565,"description":18713},"en/blog/which-sensor-gives-which-output","zELOv87LX62s1JL8sx-zxzwHWBGZRxOZe_ymF6rKPXE",{"id":18724,"title":18725,"body":18726,"description":18844,"extension":511,"meta":18845,"navigation":524,"path":18851,"seo":18852,"stem":18853,"__hash__":18854},"en_blog/en/blog/signal-selection-in-industrial-sensors.md","Signal Selection in Industrial Sensors: Why 4-20mA or 2mV/V?",{"type":8,"value":18727,"toc":18836},[18728,18730,18733,18737,18743,18754,18758,18761,18772,18776,18800,18804,18807,18822,18824,18827],[11,18729,14],{"id":13},[16,18731,18732],{},"One of the most important questions you encounter when designing a system is: \"Which signal type should I use?\" The reliability of 4-20mA or the raw precision of mV/V? This choice is an engineering decision that determines not only your wiring preference, but also the total cost and accuracy of your system. We examine why certain signals have become standard with their technical reasons.",[11,18734,18736],{"id":18735},"why-4-20ma-for-remote-monitoring","Why 4-20mA? (For Remote Monitoring)",[16,18738,18739,18740,472],{},"The biggest reason why 4-20mA is the \"golden standard\" in industry is its ",[93,18741,18742],{},"independence from electrical resistance",[40,18744,18745,18748,18751],{},[43,18746,18747],{},"Whether your cable length is 10 meters or 500 meters; the sent 12mA current reaches the receiver as 12mA.",[43,18749,18750],{},"If it were voltage (0-10V), a voltage drop would occur on the cable resistance and your data would be read incorrectly.",[43,18752,18753],{},"Therefore, if there is a distance between the sensor and the PLC, your choice should always be 4-20mA.",[11,18755,18757],{"id":18756},"why-2mvv-or-3mvv-for-raw-precision","Why 2mV/V or 3mV/V? (For Raw Precision)",[16,18759,18760],{},"Almost all high-precision sensors such as loadcells give ratiometric mV/V output.",[40,18762,18763,18769],{},[43,18764,18765,18768],{},[93,18766,18767],{},"Reason",": These sensors measure physical deformation. Passing an intermediate transmitter layer and converting it to current (4-20mA) can add extra electronic noise and error margin to the signal.",[43,18770,18771],{},"For the most precise measurement, the transmitter must be as close to the sensor as possible and must read the raw mV/V signal directly with a 24-bit ADC.",[11,18773,18775],{"id":18774},"decision-guide-for-signal-selection","Decision Guide for Signal Selection",[176,18777,18778,18791],{},[43,18779,18780,18783,18784,18786,18787,472],{},[93,18781,18782],{},"Is Precision Priority?",": If your answer is yes (e.g., laboratory scale or high-precision tests), use a sensor with ",[93,18785,8127],{}," output and a data acquisition device with a high bit value such as ",[93,18788,18789],{},[463,18790,466],{"href":1613},[43,18792,18793,18796,18797,18799],{},[93,18794,18795],{},"Are Distance and Noise Priority?",": If your answer is yes (e.g., a large factory site or outdoor environment), prefer a transmitter with ",[93,18798,18308],{}," output.",[11,18801,18803],{"id":18802},"flexibility-in-signal-conversion-with-amazeng","Flexibility in Signal Conversion with Amazeng",[16,18805,18806],{},"As Amazeng, we know your field constraints. That's why we designed our products to work hybrid:",[40,18808,18809],{},[43,18810,18811,18815,18816,18818,18819,18821],{},[93,18812,18813],{},[463,18814,471],{"href":1723},", when placed in the field, reads the mV/V signal with millimeter precision and transfers it either as ",[93,18817,18308],{}," analog to the PLC or to your SCADA system via ",[93,18820,10216],{}," so that the error margin is zero.",[11,18823,444],{"id":443},[16,18825,18826],{},"Signal selection should be made according to the technical requirements of the application. Wrong signal selection leads to data errors that cannot be corrected with software.",[16,18828,18829,18830,8017,18833,472],{},"To construct the most accurate signal architecture for your facility and to choose the appropriate transmitters, you can ",[463,18831,18832],{"href":17543},"examine our technical documents",[463,18834,18835],{"href":1628},"consult our engineers directly",{"title":38,"searchDepth":279,"depth":279,"links":18837},[18838,18839,18840,18841,18842,18843],{"id":13,"depth":279,"text":14},{"id":18735,"depth":279,"text":18736},{"id":18756,"depth":279,"text":18757},{"id":18774,"depth":279,"text":18775},{"id":18802,"depth":279,"text":18803},{"id":443,"depth":279,"text":444},"Signal selection strategies in industrial sensors from an engineering perspective and why certain signals have become standards.",{"date":18846,"author":514,"readTime":297,"tags":18847},"2025-12-10",[18848,18308,8127,18849,18850],"Signal Selection","Sensor Design","Engineering Guide","/en/blog/signal-selection-in-industrial-sensors",{"title":18725,"description":18844},"en/blog/signal-selection-in-industrial-sensors","jWAqEnk0wbcRurb0HD_EKC84Jks2N1edrWmv_tarCYg",{"id":18856,"title":18857,"body":18858,"description":18956,"extension":511,"meta":18957,"navigation":524,"path":18964,"seo":18965,"stem":18966,"__hash__":18967},"en_blog/en/blog/why-24-bit-analog-to-digital-module.md","Why 24-bit Analog to Digital Module? The Chemistry of Precision Measurement",{"type":8,"value":18859,"toc":18949},[18860,18862,18869,18873,18876,18889,18892,18896,18916,18920,18923,18938,18940,18943],[11,18861,14],{"id":13},[16,18863,18864,18865,18868],{},"When moving physical magnitudes in the analog world to the digital world, our most important limit is \"resolution.\" How small pieces an analog signal is divided into affects the accuracy of your measurement. 12-bit or 16-bit systems, which were standard in the past, have difficulty meeting today's precise engineering needs. So why should you use a ",[93,18866,18867],{},"24-bit Analog to Digital Module","? Let's solve this \"precision chemistry\" together.",[11,18870,18872],{"id":18871},"resolution-why-does-the-number-of-steps-matter","Resolution: Why Does the Number of Steps Matter?",[16,18874,18875],{},"Resolution refers to how many steps a measurement range is divided into:",[40,18877,18878,18884],{},[43,18879,18880,18883],{},[93,18881,18882],{},"16-bit",": 65,536 steps.",[43,18885,18886,18888],{},[93,18887,665],{},": 16,777,216 steps!",[16,18890,18891],{},"This massive difference means that while measuring a weight of 10 kg; while you can see changes of approximately 0.15 grams in a 16-bit system, you can see changes at the microgram (mg) level in a 24-bit system.",[11,18893,18895],{"id":18894},"why-should-you-choose-24-bit","Why Should You Choose 24-bit?",[176,18897,18898,18904,18910],{},[43,18899,18900,18903],{},[93,18901,18902],{},"Dynamic Range",": You can read even very small signals (micro-volt level) without losing them in the noise. Numerically more steps capture even the slightest oscillations of the data.",[43,18905,18906,18909],{},[93,18907,18908],{},"Digital Gain",": While hardware amplification of the signal causes noise, 24-bit resolution reads the data in such detail that even when you \"zoom\" via software, the data is not corrupted.",[43,18911,18912,18915],{},[93,18913,18914],{},"Preparation for the Future",": Industry 4.0 and AI applications always need more and more detailed data for analysis.",[11,18917,18919],{"id":18918},"product-placement-ultra-precise-data-acquisition-with-zma-series","Product Placement: Ultra-Precise Data Acquisition with ZMA Series",[16,18921,18922],{},"At Amazeng, we have standardized 24-bit technology in all data acquisition devices we develop.",[40,18924,18925,18932],{},[43,18926,18927,18931],{},[93,18928,18929],{},[463,18930,466],{"href":1613},": Not only offers 24-bit resolution, but can also perform 1000 samplings per second. This means \"both very precise and very fast\" measurement.",[43,18933,18934,18937],{},[93,18935,18936],{},"Low-Noise Design",": It is not enough for an ADC module to be only 24-bit; the electrical design on the board must also be made in such a way as not to compromise this precision (low-noise). ZMA series reflects all the power of 24-bit to the field with special isolation and signal cleaning layers.",[11,18939,444],{"id":443},[16,18941,18942],{},"The rule \"you cannot control what you cannot measure\" applies in engineering. Using a 24-bit Analog to Digital Module is like removing the blindfold from your system's eyes and giving it microscopic vision capability.",[16,18944,18945,18946,472],{},"Would you like to examine our 24-bit ADC solutions for your sensitive test systems or projects requiring high resolution? You can determine the most suitable configuration for your project by ",[463,18947,18948],{"href":1628},"meeting with our technical team",{"title":38,"searchDepth":279,"depth":279,"links":18950},[18951,18952,18953,18954,18955],{"id":13,"depth":279,"text":14},{"id":18871,"depth":279,"text":18872},{"id":18894,"depth":279,"text":18895},{"id":18918,"depth":279,"text":18919},{"id":443,"depth":279,"text":444},"A technical review of the importance of 24-bit resolution in industrial data acquisition, its advantages, and why 16-bit systems represent an insufficient solution.",{"date":18958,"author":514,"readTime":303,"tags":18959},"2025-12-09",[18960,18961,2512,18962,18963],"24-bit ADC","Analog Digital Module","Precision Measurement","ZMA Series","/en/blog/why-24-bit-analog-to-digital-module",{"title":18857,"description":18956},"en/blog/why-24-bit-analog-to-digital-module","X0diJ5YfAIA3lcDpsrxXvmsn5G3ZNQT2TVGmWv7w4vE",{"id":18969,"title":18970,"body":18971,"description":19079,"extension":511,"meta":19080,"navigation":524,"path":19084,"seo":19085,"stem":19086,"__hash__":19087},"en_blog/en/blog/zma-data-acquisition-high-speed-adc.md","ZMA Data Acquisition: High-Speed Analog Digital Module Applications",{"type":8,"value":18972,"toc":19070},[18973,18975,18986,18990,18993,19000,19004,19007,19011,19031,19035,19046,19057,19059,19062],[11,18974,14],{"id":13},[16,18976,18977,18978,18980,18981,18985],{},"While some industrial processes take place in seconds, some have dynamic movements where even microseconds are critical. The moment of impact of a press machine, the fracture test of a material, or a sudden pressure fluctuation... To capture these moments, you need an ",[93,18979,18961],{}," that is not only precise but also very fast. Discover the power of the Amazeng ",[93,18982,18983],{},[463,18984,466],{"href":1613}," family in applications requiring high speed.",[11,18987,18989],{"id":18988},"why-is-speed-critical","Why is Speed Critical?",[16,18991,18992],{},"A slow data acquisition device can miss the peaks of the signal.",[40,18994,18995],{},[43,18996,18997,18999],{},[93,18998,18596],{},": If the force goes up and down to maximum for 1 millisecond during a crash test, a device that reads 10 times per second (10 Hz) will never see this moment. Result: Wrong analysis and unsafe product design.",[11,19001,19003],{"id":19002},"zma-series-harmony-of-speed-and-precision","ZMA Series: Harmony of Speed and Precision",[16,19005,19006],{},"The ZMA series is designed with a sampling rate of 1000 Hz (1000 samples per second). This speed offers \"real-time\" monitoring performance for 99% of industrial applications.",[24,19008,19010],{"id":19009},"application-areas","Application Areas:",[176,19012,19013,19019,19025],{},[43,19014,19015,19018],{},[93,19016,19017],{},"Dynamic Weighing",": While weighing on moving belts, high speed is mandatory to filter vibrations and find the correct weight in seconds.",[43,19020,19021,19024],{},[93,19022,19023],{},"Force and Tension Tests",": In material testing laboratories, ZMA's 1kHz speed is ideal for capturing the maximum force at the moment of rupture.",[43,19026,19027,19030],{},[93,19028,19029],{},"Machine Health Monitoring",": It provides the opportunity to intervene before malfunctions occur by following instantaneous vibration changes in motor bearings.",[11,19032,19034],{"id":19033},"product-feature-instant-analysis-with-zma-desk","Product Feature: Instant Analysis with ZMA-Desk",[16,19036,19037,19038,19042,19043,19045],{},"Visualizing this data is as important as collecting high-speed data. Along with our ",[93,19039,19040],{},[463,19041,466],{"href":1613}," devices, the ",[93,19044,18101],{}," software:",[40,19047,19048,19051,19054],{},[43,19049,19050],{},"Reflects live graphics to the screen without millisecond delay.",[43,19052,19053],{},"Automatically marks the highest measured value with the \"Peak Hold\" feature.",[43,19055,19056],{},"Saves thousands of data per second to your computer with high stability over USB (Datalogging).",[11,19058,444],{"id":443},[16,19060,19061],{},"Speed is as important as data resolution. If you want to take control of processes that pass in the blink of an eye, you need more than standard modules.",[16,19063,19064,19065,8017,19067,472],{},"To get more information about your high-speed data acquisition needs and the performance of the ZMA series, ",[463,19066,17836],{"href":1613},[463,19068,19069],{"href":1628},"consult our experts",{"title":38,"searchDepth":279,"depth":279,"links":19071},[19072,19073,19074,19077,19078],{"id":13,"depth":279,"text":14},{"id":18988,"depth":279,"text":18989},{"id":19002,"depth":279,"text":19003,"children":19075},[19076],{"id":19009,"depth":285,"text":19010},{"id":19033,"depth":279,"text":19034},{"id":443,"depth":279,"text":444},"The importance of high-speed data acquisition in industrial processes requiring millisecond precision and calculations of ZMA series performance in this field.",{"date":19081,"author":514,"readTime":297,"tags":19082},"2025-12-08",[17113,18558,19083,662,18963],"DAQ","/en/blog/zma-data-acquisition-high-speed-adc",{"title":18970,"description":19079},"en/blog/zma-data-acquisition-high-speed-adc","gaOj0_nfcUcLVgUTsaC0Ra1X8ebZWTv0ro6G_ior2kc",{"id":19089,"title":19090,"body":19091,"description":19232,"extension":511,"meta":19233,"navigation":524,"path":19239,"seo":19240,"stem":19241,"__hash__":19242},"en_blog/en/blog/3-common-mistakes-in-analog-digital-conversion.md","3 Common Mistakes When Converting Analog Signals to Digital",{"type":8,"value":19092,"toc":19224},[19093,19095,19098,19102,19105,19124,19128,19131,19153,19157,19160,19183,19187,19190,19210,19212,19215],[11,19094,14],{"id":13},[16,19096,19097],{},"Converting an analog signal into digital data consists of more than just using a ready-made module. An incorrectly designed digitizing process will lead you to wrong results, no matter how high-quality your sensor is. We examine 3 common mistakes that we frequently encounter in the field and that \"poison\" the accuracy of data with technical reasons.",[11,19099,19101],{"id":19100},"_1-grounding-and-isolation-errors-ground-loops","1. Grounding and Isolation Errors (Ground Loops)",[16,19103,19104],{},"The biggest enemy of the analog signal is the ground potential differences in the system.",[40,19106,19107,19113,19119],{},[43,19108,19109,19112],{},[93,19110,19111],{},"Mistake",": Grounding the transmitter and ADC module from different sources causes a \"noise\" overlap on the signal.",[43,19114,19115,19118],{},[93,19116,19117],{},"Result",": Constantly oscillating, unstable values on the screen.",[43,19120,19121,19123],{},[93,19122,14816],{},": Using transmitters with isolated inputs or bringing the whole system together at a single star grounding point.",[11,19125,19127],{"id":19126},"_2-wrong-sampling-rate-aliasing","2. Wrong Sampling Rate (Aliasing)",[16,19129,19130],{},"This is the mismatch between the change rate of the signal and the sampling rate of the ADC.",[40,19132,19133,19138,19143],{},[43,19134,19135,19137],{},[93,19136,19111],{},": Trying to read a rapidly changing signal (e.g., vibration) only a few times per second.",[43,19139,19140,19142],{},[93,19141,19117],{},": Due to the phenomenon called \"aliasing,\" low-frequency imaginary fluctuations that do not exist appear as data.",[43,19144,19145,19147,19148,19152],{},[93,19146,14816],{},": Choosing devices such as the ",[93,19149,19150],{},[463,19151,18963],{"href":1613}," that sample at least 2 times (preferably much more) the signal frequency in accordance with the Nyquist theorem.",[11,19154,19156],{"id":19155},"_3-impedance-mismatch-and-signal-losses","3. Impedance Mismatch and Signal Losses",[16,19158,19159],{},"Mismatch between sensor output resistance and transmitter input resistance.",[40,19161,19162,19167,19172],{},[43,19163,19164,19166],{},[93,19165,19111],{},": Connecting a loadcell with mV/V output to an ordinary analog card with low input impedance.",[43,19168,19169,19171],{},[93,19170,19117],{},": Signal attenuation and low-resolution data.",[43,19173,19174,19176,19177,19182],{},[93,19175,14816],{},": Using special ",[93,19178,19179],{},[463,19180,19181],{"href":1723},"GDT Digital Transmitters"," with high input impedance and capable of ratiometric measurement.",[11,19184,19186],{"id":19185},"no-room-for-mistakes-with-amazeng","No Room for Mistakes with Amazeng",[16,19188,19189],{},"Amazeng engineering prevents these mistakes while still in the hardware design phase:",[40,19191,19192,19198,19204],{},[43,19193,19194,19197],{},[93,19195,19196],{},"Full Isolation",": Our devices have galvanic isolation at industrial standards.",[43,19199,19200,19203],{},[93,19201,19202],{},"Filter Technology",": Hardware and software \"anti-aliasing\" filters are available to prevent fake signals (aliasing).",[43,19205,19206,19209],{},[93,19207,19208],{},"24-bit Stability",": Offers high resolution enough to absorb even small signal fluctuations caused by impedance.",[11,19211,444],{"id":443},[16,19213,19214],{},"Correct data is the result of correct design. Erroneous measurements not only provide wrong information, but also jeopardize the safety of your system.",[16,19216,19217,19218,8017,19221,472],{},"To overcome the challenges in the digitization process and to detect errors in your system, ",[463,19219,19220],{"href":17543},"take a look at our technical documents",[463,19222,19223],{"href":1628},"contact us to benefit from our consultancy service",{"title":38,"searchDepth":279,"depth":279,"links":19225},[19226,19227,19228,19229,19230,19231],{"id":13,"depth":279,"text":14},{"id":19100,"depth":279,"text":19101},{"id":19126,"depth":279,"text":19127},{"id":19155,"depth":279,"text":19156},{"id":19185,"depth":279,"text":19186},{"id":443,"depth":279,"text":444},"Basic mistakes made in the process of converting analog signals to digital (digitizing) in industrial automation projects that compromise data accuracy.",{"date":19234,"author":514,"readTime":297,"tags":19235},"2025-12-07",[662,19236,19237,620,19238],"Digitizing","Erroneous Measurement","Engineering Mistakes","/en/blog/3-common-mistakes-in-analog-digital-conversion",{"title":19090,"description":19232},"en/blog/3-common-mistakes-in-analog-digital-conversion","ArQU823okmuvzknncuKG7kwKR2OTaYYS08EPDwLW8yY",{"id":19244,"title":19245,"body":19246,"description":19371,"extension":511,"meta":19372,"navigation":524,"path":19378,"seo":19379,"stem":19380,"__hash__":19381},"en_blog/en/blog/adc-integration-and-data-processing-in-embedded-systems.md","Analog to Digital Module Integration and Data Processing in Embedded Systems",{"type":8,"value":19247,"toc":19360},[19248,19250,19253,19257,19260,19264,19267,19271,19281,19289,19293,19301,19305,19313,19327,19331,19334,19349,19351,19354],[11,19249,14],{"id":13},[16,19251,19252],{},"Even if everything is flawless on the hardware side, the raw numerical data coming from the ADC is not yet meaningful information for the end user. Processing, filtering, and converting this data into a physical unit is the task of embedded software. Discover the data processing strategies used by Amazeng engineers in the ZMA and GDT series and the technical depth of this process.",[11,19254,19256],{"id":19255},"journey-from-raw-data-to-meaningful-information","Journey from Raw Data to Meaningful Information",[16,19258,19259],{},"The data coming from the ADC module is usually a large integer between 0 and 16,777,215 (for 24-bit). The processing steps of this raw data are:",[24,19261,19263],{"id":19262},"_1-conditional-filtering-preprocessing","1. Conditional Filtering (Preprocessing)",[16,19265,19266],{},"Before the data is calibrated, it is passed through low-pass or moving average filters to clean up hardware noise. This allows the reading to be more stable.",[24,19268,19270],{"id":19269},"_2-application-of-calibration-coefficients","2. Application of Calibration Coefficients",[16,19272,19273,19274,467,19277,19280],{},"Software converts raw data into physical units using pre-recorded ",[93,19275,19276],{},"Zero",[93,19278,19279],{},"Span"," coefficients.",[40,19282,19283],{},[43,19284,19285,19288],{},[93,19286,19287],{},"Formula",": $MeasuredValue = (RawData - ZeroPoint) \\times CalibrationCoefficient$",[24,19290,19292],{"id":19291},"_3-real-time-signal-processing","3. Real-Time Signal Processing",[16,19294,19295,19296,19300],{},"Especially in high-speed devices like ",[93,19297,19298],{},[463,19299,466],{"href":1613},", \"Peak\" and \"Valley\" values are calculated instantaneously over the data coming every millisecond.",[11,19302,19304],{"id":19303},"strong-architecture-in-embedded-software-zephyr-rtos","Strong Architecture in Embedded Software: Zephyr RTOS",[16,19306,19307,19308,19312],{},"As Amazeng, we use ",[93,19309,19310],{},[463,19311,18359],{"href":6115}," in the firmware layer. This modern operating system offers us the following advantages in ADC integration:",[40,19314,19315,19321],{},[43,19316,19317,19320],{},[93,19318,19319],{},"Multi-threading",": The data reading process works in a high-priority thread, while Modbus communication or screen update works in different threads. In this way, no data loss occurs.",[43,19322,19323,19326],{},[93,19324,19325],{},"Standard ADC API",": Our signal processing algorithms in the upper layer do not change even if we use different ADC chips.",[11,19328,19330],{"id":19329},"product-placement-smart-firmware-layer-of-gdt-and-zma","Product Placement: \"Smart\" Firmware Layer of GDT and ZMA",[16,19332,19333],{},"Our devices are not just \"converters,\" but mini computers:",[40,19335,19336,19343],{},[43,19337,19338,19342],{},[93,19339,19340],{},[463,19341,471],{"href":1723},": The adaptive filter algorithms contained within it can set the filter hardness itself by analyzing the vibration characteristic in the field.",[43,19344,19345,19348],{},[93,19346,19347],{},"Synchronization",": In the ZMA series, data coming from multiple channels is synchronized with a timestamp, so the correlation between them can be analyzed clearly.",[11,19350,444],{"id":443},[16,19352,19353],{},"Data processing in embedded systems is a perfect dance between hardware and software. A transmitter equipped with correct algorithms produces laboratory-precision results even in the most challenging field conditions.",[16,19355,19356,19359],{},[463,19357,19358],{"href":1628},"Talk to our engineering team"," for our embedded system solutions and special firmware needs.",{"title":38,"searchDepth":279,"depth":279,"links":19361},[19362,19363,19368,19369,19370],{"id":13,"depth":279,"text":14},{"id":19255,"depth":279,"text":19256,"children":19364},[19365,19366,19367],{"id":19262,"depth":285,"text":19263},{"id":19269,"depth":285,"text":19270},{"id":19291,"depth":285,"text":19292},{"id":19303,"depth":279,"text":19304},{"id":19329,"depth":279,"text":19330},{"id":443,"depth":279,"text":444},"How raw data coming from ADC modules is processed in the embedded software world, calibration algorithms, and signal processing techniques.",{"date":19373,"author":514,"readTime":515,"tags":19374},"2025-12-06",[1645,18466,19375,19376,19377],"Signal Processing","Firmware","Data Analysis","/en/blog/adc-integration-and-data-processing-in-embedded-systems",{"title":19245,"description":19371},"en/blog/adc-integration-and-data-processing-in-embedded-systems","mw3p_ql5JTSDC9lmmo4mcMjcmJuzplxFZ9Mxv6yn1P8",{"id":19383,"title":19384,"body":19385,"description":19481,"extension":511,"meta":19482,"navigation":524,"path":19487,"seo":19488,"stem":19489,"__hash__":19490},"en_blog/en/blog/loadcell-and-transmitter-compatibility-in-milk-tank-automation.md","Loadcell and Transmitter Compatibility in Milk Tank Automation",{"type":8,"value":19386,"toc":19472},[19387,19389,19396,19400,19403,19417,19421,19429,19433,19453,19457,19460,19462,19465],[11,19388,14],{"id":13},[16,19390,19391,19392,472],{},"Stock management in milk collection and processing facilities is the most critical process that determines the profitability of the enterprise. Choosing weight-based loadcell systems instead of liter-based flowmeters provides great advantages in terms of hygiene and precision. However, the heart of this system is the control unit that manages the data coming from the loadcell. Discover the perfect compatibility with the Amazeng ",[93,19393,19394],{},[463,19395,17801],{"href":17800},[11,19397,19399],{"id":19398},"why-weight-based-level-measurement","Why Weight-Based Level Measurement?",[16,19401,19402],{},"Foaming of milk, density changes, or mixer movements inside the tank can mislead ultrasonic or radar-type level sensors.",[40,19404,19405,19411],{},[43,19406,19407,19410],{},[93,19408,19409],{},"Weighing Advantage",": Loadcells placed on the legs of the tank are based on the law of gravity. Even if the liquid foams or its temperature changes, the weight always reflects the truth.",[43,19412,19413,19416],{},[93,19414,19415],{},"Hygiene",": Sensors do not need to enter the milk. Since measurement is made from outside the tank (from its legs), the risk of contamination is zero.",[11,19418,19420],{"id":19419},"sk01-series-special-solution-for-the-milk-industry","SK01 Series: Special Solution for the Milk Industry",[16,19422,18075,19423,19428],{},[93,19424,19425],{},[463,19426,19427],{"href":17800},"Milk Tank Control Unit (SK01)"," developed by Amazeng engineers is much more than a load cell transmitter.",[24,19430,19432],{"id":19431},"critical-features","Critical Features:",[176,19434,19435,19441,19447],{},[43,19436,19437,19440],{},[93,19438,19439],{},"Precise Loadcell Reading",": Processes data coming from 2mV/V or 3mV/V loadcells with 24-bit resolution and offers millimeter accuracy.",[43,19442,19443,19446],{},[93,19444,19445],{},"Automatic Mixer and Cooling Control",": Relay outputs on the unit manage the operation of the mixer and the cooling system depending on temperature and time so that the milk does not spoil.",[43,19448,19449,19452],{},[93,19450,19451],{},"Fast Calibration",": When the milk truck arrives or the tank is emptied, zeroing (Tare) can be performed in seconds via the user-friendly panel.",[11,19454,19456],{"id":19455},"data-integration-and-monitoring","Data Integration and Monitoring",[16,19458,19459],{},"The SK01 series is not just a local controller. With Modbus communication support, it can transfer the fill rates of all tanks to a central SCADA system or the cloud. In this way, milk collection routes can be dynamically optimized according to the fill rates of the tanks.",[11,19461,444],{"id":443},[16,19463,19464],{},"Correct loadcell and transmitter compatibility prevents waste in the milk industry and increases operational speed. Amazeng's field-proven SK01 control units transform your milk tanks into smart data sources.",[16,19466,19467,19468,8017,19470,472],{},"To design the most suitable weighing system for your dairy or milk processing facility, ",[463,19469,17836],{"href":17800},[463,19471,1629],{"href":1628},{"title":38,"searchDepth":279,"depth":279,"links":19473},[19474,19475,19476,19479,19480],{"id":13,"depth":279,"text":14},{"id":19398,"depth":279,"text":19399},{"id":19419,"depth":279,"text":19420,"children":19477},[19478],{"id":19431,"depth":285,"text":19432},{"id":19455,"depth":279,"text":19456},{"id":443,"depth":279,"text":444},"Advantages of loadcell-based weight measurement systems and control unit integration for milk stock management in the food industry.",{"date":19483,"author":514,"readTime":303,"tags":19484},"2025-12-05",[7988,10217,2562,19485,19486],"SK01 Series","Food Automation","/en/blog/loadcell-and-transmitter-compatibility-in-milk-tank-automation",{"title":19384,"description":19481},"en/blog/loadcell-and-transmitter-compatibility-in-milk-tank-automation","nHmSzfhW0uI8ORSJ8DYwHgp5mKsUl6PRAuH_JGYR6vs",{"id":19492,"title":19493,"body":19494,"description":19612,"extension":511,"meta":19613,"navigation":524,"path":19619,"seo":19620,"stem":19621,"__hash__":19622},"en_blog/en/blog/iot-based-data-acquisition-guide.md","IoT Based Data Acquisition: Guide to Carrying Analog Data to the Cloud",{"type":8,"value":19495,"toc":19601},[19496,19498,19501,19505,19508,19512,19519,19526,19530,19533,19546,19550,19553,19557,19560,19577,19581,19587,19589,19592],[11,19497,14],{"id":13},[16,19499,19500],{},"The Internet of Things (IoT) is no longer a luxury in the industrial world, but a way to stay competitive. However, thousands of analog sensors in the field (4-20mA, Loadcell, Pressure) cannot connect directly to the internet. The journey of data to the cloud requires a correct \"bridge.\" In this guide, we examine the most reliable and scalable ways to carry data from the analog field to the digital cloud.",[11,19502,19504],{"id":19503},"architecture-of-the-data-journey","Architecture of the Data Journey",[16,19506,19507],{},"For a sensor data to reach the cloud, it must pass through 3 basic layers:",[24,19509,19511],{"id":19510},"layer-1-digitizing","Layer 1: Digitizing",[16,19513,19514,19515,472],{},"Converting the analog signal (for example, a tank level information) into digital data with a high-precision ",[93,19516,19517],{},[463,19518,17047],{"href":1723},[40,19520,19521],{},[43,19522,19523,19525],{},[93,19524,17748],{},": Incorrectly digitized data goes to the cloud as \"noise\" and disrupts all analyses.",[24,19527,19529],{"id":19528},"layer-2-communication-and-gateway","Layer 2: Communication and Gateway",[16,19531,19532],{},"Transferring the digitized data from a local network (RS485, Ethernet) to the IoT Gateway.",[40,19534,19535],{},[43,19536,19537,19540,19541,19545],{},[93,19538,19539],{},"Protocols",": Modbus RTU/TCP and MQTT are the strongest players of this layer. Our ",[93,19542,19543],{},[463,19544,466],{"href":1613}," devices speak perfectly with almost all IoT Gateway and PLC systems on the market thanks to the Modbus protocol.",[24,19547,19549],{"id":19548},"layer-3-cloud-and-visualization","Layer 3: Cloud and Visualization",[16,19551,19552],{},"Transmission of data coming via the Gateway (in JSON or binary format) to cloud servers. Here, the data is now ready for \"Big Data\" analytics.",[11,19554,19556],{"id":19555},"where-are-amazeng-devices-in-the-iot-architecture","Where are Amazeng Devices in the IoT Architecture?",[16,19558,19559],{},"Amazeng products are positioned at the \"Edge\" point of the IoT pyramid. We are not just transmitting the data, we are preparing it for the cloud:",[40,19561,19562,19571],{},[43,19563,19564,1927,19567,19570],{},[93,19565,19566],{},"Pre-processing (Edge Processing)",[93,19568,19569],{},"ZMA series"," reduces bandwidth cost by sending only meaningful 'average' or 'peak' values to the cloud while reading 1000 data per second.",[43,19572,19573,19576],{},[93,19574,19575],{},"Secure Communication",": While our Modbus TCP-based devices provide a secure data flow within the local network, they offer the cleanest data for your Gateway device to transmit the data encrypted to the outside world.",[11,19578,19580],{"id":19579},"a-real-application-scenario-remote-factory-monitoring","A Real Application Scenario: Remote Factory Monitoring",[16,19582,19583,19584,19586],{},"Imagine monitoring machine vibration data in different cities in a multi-location manufacturing facility from a single center. Our ",[93,19585,466],{}," devices read raw vibration at each location, analyze it, and transfer it to the Gateway in the building via Modbus. The Gateway carries this data to the AWS or Azure cloud via MQTT. Result: You can instantly monitor the health status of all your factories from your smartphone.",[11,19588,444],{"id":443},[16,19590,19591],{},"Carrying analog data to the cloud is transforming the reality in the field into a digital twin. With a correct transmitter and communication infrastructure, this process returns to your enterprise as predictive maintenance and operational efficiency.",[16,19593,19594,19597,19598,472],{},[463,19595,19596],{"href":17543},"Examine our solutions"," to include your analog sensors in the IoT world or ",[463,19599,19600],{"href":1628},"get project support from our technical team",{"title":38,"searchDepth":279,"depth":279,"links":19602},[19603,19604,19609,19610,19611],{"id":13,"depth":279,"text":14},{"id":19503,"depth":279,"text":19504,"children":19605},[19606,19607,19608],{"id":19510,"depth":285,"text":19511},{"id":19528,"depth":285,"text":19529},{"id":19548,"depth":285,"text":19549},{"id":19555,"depth":279,"text":19556},{"id":19579,"depth":279,"text":19580},{"id":443,"depth":279,"text":444},"A technical guide on how analog sensor data in the field is transferred to the cloud via IoT devices and gateways and the architecture of this process.",{"date":19614,"author":514,"readTime":515,"tags":19615},"2025-12-04",[2441,19616,18558,19617,19618],"Cloud Data","Gateway","Industrial Data","/en/blog/iot-based-data-acquisition-guide",{"title":19493,"description":19612},"en/blog/iot-based-data-acquisition-guide","v5VbHmidV0SGN6VMqppbjlKKRN4oDB7GugzyDbx58X0",{"id":19624,"title":19625,"body":19626,"description":19715,"extension":511,"meta":19716,"navigation":524,"path":19719,"seo":19720,"stem":19721,"__hash__":19722},"en_blog/en/blog/tinyml-ai-revolution-at-the-edge.md","TinyML: Artificial Intelligence Revolution at the Edge in Industrial Sensors",{"type":8,"value":19627,"toc":19708},[19628,19630,19636,19638,19640,19657,19659,19678,19682,19685,19698,19700,19703],[11,19629,14],{"id":13},[16,19631,19632,19633,19635],{},"When artificial intelligence is mentioned, massive servers and powerful graphics cards come to mind. However, such a big power source is not contained within a transmitter or vibration sensor in the industrial field. This is where ",[93,19634,1544],{}," comes in. TinyML is the art of running machine learning models on microcontrollers (MCUs) with only a few kilobytes of memory. This technology transforms industrial sensors into smart devices that \"understand what they see\" rather than just \"looking.\"",[11,19637,1549],{"id":1548},[16,19639,1552],{},[176,19641,19642,19647,19652],{},[43,19643,19644,19646],{},[93,19645,1559],{},": Analyzes the data on site without sending it to the cloud. This means response time in milliseconds (zero latency).",[43,19648,19649,19651],{},[93,19650,1565],{},": Transmits data only when an abnormal situation (fault, leak, etc.) is detected. This reduces the energy and communication cost of IoT systems.",[43,19653,19654,19656],{},[93,19655,1571],{},": Since critical data is processed without leaving the device, cyber security risks are minimized.",[11,19658,1576],{"id":1575},[40,19660,19661,19666,19672],{},[43,19662,19663,19665],{},[93,19664,1583],{},": From the vibration of a motor, it can notice a previously unseen fault mode in seconds.",[43,19667,19668,19671],{},[93,19669,19670],{},"Smart Filtering",": It uses deep learning models instead of classic filters to distinguish noise from real data (for example, the difference between churning in the tank and real filling).",[43,19673,19674,19677],{},[93,19675,19676],{},"Sound Analysis",": Sound-based analysis systems that understand which bearing needs lubrication from the sounds made by machines in the factory.",[11,19679,19681],{"id":19680},"amazeng-and-the-future-with-ai","Amazeng and the Future with AI",[16,19683,19684],{},"At Amazeng, we are making our data acquisition devices \"Edge AI\" compatible.",[40,19686,19687,19695],{},[43,19688,19689,19690,19694],{},"High-resolution 24-bit data coming from our ",[93,19691,19692],{},[463,19693,466],{"href":1613}," devices provide the highest quality training material for TinyML models.",[43,19696,19697],{},"The modern MCU infrastructure we use in our embedded system architecture allows libraries such as TensorFlow Lite Micro and Edge Impulse to run on our devices.",[11,19699,444],{"id":443},[16,19701,19702],{},"TinyML is a quiet revolution that increases the \"IQ\" of industrial sensors. In the factories of the future, devices will not only be interconnected, but each will also have a small artificial intelligence in its own area of responsibility.",[16,19704,19705,19707],{},[463,19706,18112],{"href":1628}," to get more information about your artificial intelligence-supported sensor projects and our TinyML-based solutions.",{"title":38,"searchDepth":279,"depth":279,"links":19709},[19710,19711,19712,19713,19714],{"id":13,"depth":279,"text":14},{"id":1548,"depth":279,"text":1549},{"id":1575,"depth":279,"text":1576},{"id":19680,"depth":279,"text":19681},{"id":443,"depth":279,"text":444},"TinyML, the art of running artificial intelligence on microcontrollers (MCUs) with limited resources, and its transformative power in industrial sensors.",{"date":19717,"author":514,"readTime":303,"tags":19718},"2025-12-03",[1641,1642,1643,1644,1645],"/en/blog/tinyml-ai-revolution-at-the-edge",{"title":19625,"description":19715},"en/blog/tinyml-ai-revolution-at-the-edge","Ing82VGB6e09pHB2tpG-VD7lKpnX_bbrde_U0VvZm2o",{"id":19724,"title":19725,"body":19726,"description":19817,"extension":511,"meta":19818,"navigation":524,"path":19823,"seo":19824,"stem":19825,"__hash__":19826},"en_blog/en/blog/predictive-maintenance-with-npu-mcus.md","Predictive Maintenance with NPU Supported MCUs: Predicting the Future",{"type":8,"value":19727,"toc":19810},[19728,19730,19737,19741,19744,19752,19756,19759,19779,19783,19786,19799,19801,19804],[11,19729,14],{"id":13},[16,19731,19732,19733,19736],{},"In the industrial world, an unplanned downtime of a machine sometimes means a loss of millions of dollars. \"Predictive Maintenance,\" developed to prevent this loss, used to be done by sending the data to the cloud and analyzing it there. However, ",[93,19734,19735],{},"NPU (Neural Processing Unit)"," units found in next-generation microcontrollers (MCU) allow us to perform this analysis directly at the transmitter layer on the machine.",[11,19738,19740],{"id":19739},"what-is-npu-and-why-is-it-a-revolution","What is NPU and Why is it a Revolution?",[16,19742,19743],{},"NPU is a hardware unit that performs mathematical operations of neural networks (matrix multiplications, activation functions, etc.) 100 times faster and with 10 times less energy than the CPU.",[40,19745,19746],{},[43,19747,19748,19751],{},[93,19749,19750],{},"Big Difference",": A standard MCU struggles and slows down while running a complex artificial intelligence model. An NPU-supported MCU, on the other hand, can analyze thousands of vibration data per second in real time and say instantly \"this bearing will fail within 2 weeks.\"",[11,19753,19755],{"id":19754},"a-new-era-in-predictive-maintenance","A New Era in Predictive Maintenance",[16,19757,19758],{},"NPU-supported smart transmitters and data acquisition devices provide:",[176,19760,19761,19767,19773],{},[43,19762,19763,19766],{},[93,19764,19765],{},"Continuous Monitoring",": Not just at certain intervals, but 7/24 uninterrupted \"deep analysis.\"",[43,19768,19769,19772],{},[93,19770,19771],{},"Dynamic Threshold Values",": While classic systems work with fixed limits, NPU-supported systems learn the normal behavior of the machine at every stage (operating load, temperature, etc.) and detect anomalies accordingly.",[43,19774,19775,19778],{},[93,19776,19777],{},"Energy Efficiency",": Thanks to the NPU, much smarter operations can be done without increasing the battery life or energy consumption of the device.",[11,19780,19782],{"id":19781},"amazeng-and-npu-technology","Amazeng and NPU Technology",[16,19784,19785],{},"As the Amazeng engineering team, we closely follow and integrate processor architectures with NPU accelerators (such as STM32-N6) in our next-generation hardware designs.",[40,19787,19788,19796],{},[43,19789,19790,19791,19795],{},"The high-resolution reading capability of our ",[93,19792,19793],{},[463,19794,466],{"href":1613}," platform provides the purest raw data for NPU-based algorithms.",[43,19797,19798],{},"In our future projects, we aim to place these hardware artificial intelligence units directly into our noise filtering and calibration processes.",[11,19800,444],{"id":443},[16,19802,19803],{},"Maintenance teams in future factories will not wait for machines to break down. With notifications from NPU-supported smart sensors, they will be able to intervene in malfunctions when there is no sign yet. This is not just an efficiency, but a radical change of mindset in the industrial world.",[16,19805,19806,19809],{},[463,19807,19808],{"href":1628},"Contact our technical experts"," for your NPU-supported predictive maintenance projects and special design needs.",{"title":38,"searchDepth":279,"depth":279,"links":19811},[19812,19813,19814,19815,19816],{"id":13,"depth":279,"text":14},{"id":19739,"depth":279,"text":19740},{"id":19754,"depth":279,"text":19755},{"id":19781,"depth":279,"text":19782},{"id":443,"depth":279,"text":444},"A technical look at how next-generation microcontrollers with neural processing units (NPU) make a difference in predictive maintenance processes.",{"date":19819,"author":514,"readTime":303,"tags":19820},"2025-12-02",[19821,19822,14979,1642,10235],"NPU","MCU","/en/blog/predictive-maintenance-with-npu-mcus",{"title":19725,"description":19817},"en/blog/predictive-maintenance-with-npu-mcus","WMHWL8efRuoCXeVPm8e4KhzNQ-st8THP3ys4aFH7tfo",{"id":19828,"title":19829,"body":19830,"description":19927,"extension":511,"meta":19928,"navigation":524,"path":19934,"seo":19935,"stem":19936,"__hash__":19937},"en_blog/en/blog/smart-transmitters-ai-noise-filtering.md","Smart Transmitters: Noise Filtering and Anomaly Detection with AI",{"type":8,"value":19831,"toc":19920},[19832,19834,19837,19841,19844,19855,19859,19862,19876,19880,19892,19906,19908,19911],[11,19833,14],{"id":13},[16,19835,19836],{},"Industrial transmitters are no longer just boxes \"carrying signals from one place to another.\" Thanks to edge computing and embedded artificial intelligence (embedded AI), transmitters have now started to \"think\" on the signal they have. So, what does putting artificial intelligence into a transmitter give us? Let's discover the revolution especially in noise filtering and anomaly detection.",[11,19838,19840],{"id":19839},"ai-supported-noise-filtering-beyond-classic-filters","AI Supported Noise Filtering: Beyond Classic Filters",[16,19842,19843],{},"Traditional transmitters use Kalman filters or simple low-pass filters (LPF) to prevent noise. However, these filters can sometimes slow down or distort real signal changes.",[40,19845,19846,19852],{},[43,19847,19848,19851],{},[93,19849,19850],{},"AI Approach",": Deep learning-based filters learn the \"characteristic noise\" in the field (e.g., the frequency of a specific motor).",[43,19853,19854],{},"In this way, it can preserve real signal responses (step response) at millisecond speeds while deleting noise. Result: A data stream that is both pristine and very fast.",[11,19856,19858],{"id":19857},"anomaly-detection-malfunctions-even-before-they-occur","Anomaly Detection: Malfunctions Even Before They Occur",[16,19860,19861],{},"A smart transmitter constantly monitors the normal operating order of the sensor it is connected to.",[176,19863,19864,19870],{},[43,19865,19866,19869],{},[93,19867,19868],{},"Sensor Aging",": It notices micro-shifts in the sensitivity of the sensor and reminds that the calibration time has come.",[43,19871,19872,19875],{},[93,19873,19874],{},"Process Deviations",": It instantly notices unusual fluctuations in a pressure or weighing signal (e.g., a blockage in the tank or mechanical friction) and sends the information \"the measurement is correct but there is an anomaly in the process\" to the SCADA.",[11,19877,19879],{"id":19878},"product-placement-amazengs-smart-signal-vision","Product Placement: Amazeng's Smart Signal Vision",[16,19881,19882,19883,467,19887,19891],{},"As Amazeng, we design our ",[93,19884,19885],{},[463,19886,471],{"href":1723},[93,19888,19889],{},[463,19890,466],{"href":1613}," platforms for this smart world of the future.",[40,19893,19894,19900],{},[43,19895,19896,19899],{},[93,19897,19898],{},"Data Quality",": The success of artificial intelligence depends on the cleanliness of the data. The 24-bit resolution offered by our devices provides the most detailed \"fingerprint\" for our AI algorithms.",[43,19901,19902,19905],{},[93,19903,19904],{},"Flexible Firmware",": The firmware infrastructure of our devices is capable of running lightweight neural networks trained according to a specific model (pattern) in the field.",[11,19907,444],{"id":443},[16,19909,19910],{},"Smart transmitters take the \"interpreting data\" load off the operators and offer them a decision-making-oriented workspace. A measurement system equipped with AI is not just an instrument, but a smart synapse in your factory's nervous system.",[16,19912,19913,19914,8017,19917,19919],{},"Examine our ",[463,19915,19916],{"href":17543},"technical documents",[463,19918,1629],{"href":1628}," to discover the smart measurement systems of the future today and to benefit from the power of artificial intelligence in your projects.",{"title":38,"searchDepth":279,"depth":279,"links":19921},[19922,19923,19924,19925,19926],{"id":13,"depth":279,"text":14},{"id":19839,"depth":279,"text":19840},{"id":19857,"depth":279,"text":19858},{"id":19878,"depth":279,"text":19879},{"id":443,"depth":279,"text":444},"Technical details of cleaning interference and real-time anomaly detection with the integration of artificial intelligence algorithms at the transmitter level.",{"date":19929,"author":514,"readTime":303,"tags":19930},"2025-12-01",[19931,1644,1583,19932,19933],"Smart Transmitter","Noise Filtering","Signal Intelligence","/en/blog/smart-transmitters-ai-noise-filtering",{"title":19829,"description":19927},"en/blog/smart-transmitters-ai-noise-filtering","LGJM2wsZdEbuDfSDJWQfa1rXUG4-RSr1nRClZbKhAAY",{"id":19939,"title":19940,"body":19941,"description":20740,"extension":511,"meta":20741,"navigation":524,"path":20746,"seo":20747,"stem":20748,"__hash__":20749},"en_blog/en/blog/sensor-performance-terminology.md","Sensor Performance Terminology: Guide to Sensitivity, Accuracy, and Resolution",{"type":8,"value":19942,"toc":20721},[19943,19945,19948,19952,19956,19959,19965,19971,20006,20010,20013,20018,20029,20035,20100,20104,20107,20110,20121,20126,20130,20136,20142,20208,20213,20224,20228,20232,20235,20240,20251,20255,20258,20263,20283,20325,20329,20332,20337,20348,20401,20405,20408,20413,20433,20438,20449,20453,20456,20461,20475,20480,20483,20535,20540,20554,20558,20561,20639,20643,20703,20705,20708,20710,20719],[11,19944,14],{"id":13},[16,19946,19947],{},"Understanding performance terminology is critically important for making the right sensor selection in industrial measurement systems. In this article, we will examine in detail the fundamental concepts that determine sensor performance.",[11,19949,19951],{"id":19950},"fundamental-performance-parameters","📊 Fundamental Performance Parameters",[24,19953,19955],{"id":19954},"_1-resolution","1. Resolution",[16,19957,19958],{},"The smallest change or smallest signal increment that the sensor can detect.",[16,19960,19961,19964],{},[93,19962,19963],{},"Example:"," If a temperature sensor has a resolution of 0.1°C, it can only detect the transition from 25.0°C to 25.1°C, not the difference between 25.05°C and 25.15°C.",[16,19966,19967,19970],{},[93,19968,19969],{},"⚠️ Important Note:"," High resolution does not mean high accuracy!",[29,19972,19974],{"className":751,"code":19973,"language":753,"meta":38,"style":38},"# Resolution calculation example\nadc_bits = 24  # 24-bit ADC\nvoltage_range = 10.0  # 10V range\nresolution = voltage_range / (2**adc_bits)\nprint(f\"Resolution: {resolution*1e6:.3f} µV\")\n# Output: Resolution: 0.596 µV\n",[36,19975,19976,19981,19986,19991,19996,20001],{"__ignoreMap":38},[270,19977,19978],{"class":272,"line":273},[270,19979,19980],{},"# Resolution calculation example\n",[270,19982,19983],{"class":272,"line":279},[270,19984,19985],{},"adc_bits = 24  # 24-bit ADC\n",[270,19987,19988],{"class":272,"line":285},[270,19989,19990],{},"voltage_range = 10.0  # 10V range\n",[270,19992,19993],{"class":272,"line":291},[270,19994,19995],{},"resolution = voltage_range / (2**adc_bits)\n",[270,19997,19998],{"class":272,"line":297},[270,19999,20000],{},"print(f\"Resolution: {resolution*1e6:.3f} µV\")\n",[270,20002,20003],{"class":272,"line":303},[270,20004,20005],{},"# Output: Resolution: 0.596 µV\n",[24,20007,20009],{"id":20008},"_2-sensitivity","2. Sensitivity",[16,20011,20012],{},"The rate of change in the sensor's output corresponding to a change in the measured input. This is usually expressed as a slope.",[16,20014,20015],{},[93,20016,20017],{},"Unit Examples:",[40,20019,20020,20023,20026],{},[43,20021,20022],{},"mV/psi (pressure sensor)",[43,20024,20025],{},"mA/°C (temperature sensor)",[43,20027,20028],{},"mV/V (loadcell)",[16,20030,20031,20034],{},[93,20032,20033],{},"High Sensitivity:"," A small change in input causes a large change in output.",[29,20036,20040],{"className":20037,"code":20038,"language":20039,"meta":38,"style":38},"language-c shiki shiki-themes github-light github-dark","// Loadcell sensitivity calculation\nfloat sensitivity = 2.0;  // mV/V\nfloat excitation = 10.0;  // V\nfloat full_scale = 100.0; // kg\n\n// Output voltage at full scale\nfloat output_voltage = sensitivity * excitation;\n// 20 mV @ 100 kg load\n\n// Voltage change per 1 kg\nfloat voltage_per_kg = output_voltage / full_scale;\n// 0.2 mV/kg\n","c",[36,20041,20042,20047,20052,20057,20062,20066,20071,20076,20081,20085,20090,20095],{"__ignoreMap":38},[270,20043,20044],{"class":272,"line":273},[270,20045,20046],{},"// Loadcell sensitivity calculation\n",[270,20048,20049],{"class":272,"line":279},[270,20050,20051],{},"float sensitivity = 2.0;  // mV/V\n",[270,20053,20054],{"class":272,"line":285},[270,20055,20056],{},"float excitation = 10.0;  // V\n",[270,20058,20059],{"class":272,"line":291},[270,20060,20061],{},"float full_scale = 100.0; // kg\n",[270,20063,20064],{"class":272,"line":297},[270,20065,775],{"emptyLinePlaceholder":524},[270,20067,20068],{"class":272,"line":303},[270,20069,20070],{},"// Output voltage at full scale\n",[270,20072,20073],{"class":272,"line":515},[270,20074,20075],{},"float output_voltage = sensitivity * excitation;\n",[270,20077,20078],{"class":272,"line":793},[270,20079,20080],{},"// 20 mV @ 100 kg load\n",[270,20082,20083],{"class":272,"line":799},[270,20084,775],{"emptyLinePlaceholder":524},[270,20086,20087],{"class":272,"line":805},[270,20088,20089],{},"// Voltage change per 1 kg\n",[270,20091,20092],{"class":272,"line":2120},[270,20093,20094],{},"float voltage_per_kg = output_voltage / full_scale;\n",[270,20096,20097],{"class":272,"line":2126},[270,20098,20099],{},"// 0.2 mV/kg\n",[24,20101,20103],{"id":20102},"_3-accuracy","3. Accuracy",[16,20105,20106],{},"How close the measurement obtained from the sensor is to the true value. It indicates the magnitude of the sensor's error.",[16,20108,20109],{},"Usually expressed as:",[40,20111,20112,20115,20118],{},[43,20113,20114],{},"Percentage: ±0.1% FS (Full Scale)",[43,20116,20117],{},"In units: ±0.5°C",[43,20119,20120],{},"Deviation from true value: ±2 LSB",[16,20122,20123,20125],{},[93,20124,19963],{}," If the sensor measures 29.8°C when the actual temperature is 30.0°C, it shows a 0.2°C error.",[24,20127,20129],{"id":20128},"_4-repeatability-and-precision","4. Repeatability and Precision",[16,20131,20132,20135],{},[93,20133,20134],{},"Repeatability:"," How consistently the sensor gives the same output when the same input is applied repeatedly under the same conditions.",[16,20137,20138,20141],{},[93,20139,20140],{},"Precision:"," Similar to repeatability, it indicates how close measurements are to each other (low dispersion).",[29,20143,20145],{"className":751,"code":20144,"language":753,"meta":38,"style":38},"import numpy as np\n\n# 10 repeated measurement example\nmeasurements = [25.1, 25.2, 25.1, 25.2, 25.1, 25.2, 25.1, 25.2, 25.1, 25.2]\ntrue_value = 25.0\n\n# Precision (standard deviation)\nprecision = np.std(measurements)\nprint(f\"Precision (σ): ±{precision:.3f}°C\")\n\n# Accuracy (average error)\naccuracy = abs(np.mean(measurements) - true_value)\nprint(f\"Accuracy Error: {accuracy:.3f}°C\")\n",[36,20146,20147,20151,20155,20160,20165,20170,20174,20179,20184,20189,20193,20198,20203],{"__ignoreMap":38},[270,20148,20149],{"class":272,"line":273},[270,20150,13988],{},[270,20152,20153],{"class":272,"line":279},[270,20154,775],{"emptyLinePlaceholder":524},[270,20156,20157],{"class":272,"line":285},[270,20158,20159],{},"# 10 repeated measurement example\n",[270,20161,20162],{"class":272,"line":291},[270,20163,20164],{},"measurements = [25.1, 25.2, 25.1, 25.2, 25.1, 25.2, 25.1, 25.2, 25.1, 25.2]\n",[270,20166,20167],{"class":272,"line":297},[270,20168,20169],{},"true_value = 25.0\n",[270,20171,20172],{"class":272,"line":303},[270,20173,775],{"emptyLinePlaceholder":524},[270,20175,20176],{"class":272,"line":515},[270,20177,20178],{},"# Precision (standard deviation)\n",[270,20180,20181],{"class":272,"line":793},[270,20182,20183],{},"precision = np.std(measurements)\n",[270,20185,20186],{"class":272,"line":799},[270,20187,20188],{},"print(f\"Precision (σ): ±{precision:.3f}°C\")\n",[270,20190,20191],{"class":272,"line":805},[270,20192,775],{"emptyLinePlaceholder":524},[270,20194,20195],{"class":272,"line":2120},[270,20196,20197],{},"# Accuracy (average error)\n",[270,20199,20200],{"class":272,"line":2126},[270,20201,20202],{},"accuracy = abs(np.mean(measurements) - true_value)\n",[270,20204,20205],{"class":272,"line":2132},[270,20206,20207],{},"print(f\"Accuracy Error: {accuracy:.3f}°C\")\n",[16,20209,20210],{},[93,20211,20212],{},"Target Analogy:",[40,20214,20215,20218,20221],{},[43,20216,20217],{},"High precision, low accuracy: Arrows outside the target but close to each other",[43,20219,20220],{},"High accuracy, low precision: Arrows scattered around the target",[43,20222,20223],{},"Ideal: Both high precision and high accuracy",[11,20225,20227],{"id":20226},"dynamic-and-operating-terms","⚡ Dynamic and Operating Terms",[24,20229,20231],{"id":20230},"_5-operating-range-span","5. Operating Range / Span",[16,20233,20234],{},"The range between the smallest and largest input values within which the sensor can accurately measure.",[16,20236,20237],{},[93,20238,20239],{},"Examples:",[40,20241,20242,20245,20248],{},[43,20243,20244],{},"Pressure sensor: 0-100 psi",[43,20246,20247],{},"Temperature sensor: -40°C to +85°C",[43,20249,20250],{},"Loadcell: 0-500 kg",[24,20252,20254],{"id":20253},"_6-latency-response-time","6. Latency / Response Time",[16,20256,20257],{},"The time it takes for the sensor to accurately reflect a new value when there is a change in input.",[16,20259,20260],{},[93,20261,20262],{},"Definitions:",[40,20264,20265,20271,20277],{},[43,20266,20267,20270],{},[93,20268,20269],{},"Rise Time (tr):"," Time for output to go from 10% to 90%",[43,20272,20273,20276],{},[93,20274,20275],{},"Settling Time:"," Time for output to stay within ±X% of final value",[43,20278,20279,20282],{},[93,20280,20281],{},"Time Constant (τ):"," Time to reach 63.2% (for first-order systems)",[29,20284,20286],{"className":20037,"code":20285,"language":20039,"meta":38,"style":38},"// ZMA Data Acquisition sampling rate\n#define SAMPLE_RATE 1000  // Hz\n#define FILTER_ORDER 4\n\n// Minimum detectable signal duration\nfloat min_signal_duration = (1.0 / SAMPLE_RATE) * FILTER_ORDER * 2;\n// ~8 ms minimum detection time\n",[36,20287,20288,20293,20301,20306,20310,20315,20320],{"__ignoreMap":38},[270,20289,20290],{"class":272,"line":273},[270,20291,20292],{},"// ZMA Data Acquisition sampling rate\n",[270,20294,20295,20298],{"class":272,"line":279},[270,20296,20297],{},"#define SAMPLE_RATE 1000",[270,20299,20300],{},"  // Hz\n",[270,20302,20303],{"class":272,"line":285},[270,20304,20305],{},"#define FILTER_ORDER 4\n",[270,20307,20308],{"class":272,"line":291},[270,20309,775],{"emptyLinePlaceholder":524},[270,20311,20312],{"class":272,"line":297},[270,20313,20314],{},"// Minimum detectable signal duration\n",[270,20316,20317],{"class":272,"line":303},[270,20318,20319],{},"float min_signal_duration = (1.0 / SAMPLE_RATE) * FILTER_ORDER * 2;\n",[270,20321,20322],{"class":272,"line":515},[270,20323,20324],{},"// ~8 ms minimum detection time\n",[24,20326,20328],{"id":20327},"_7-hysteresis","7. Hysteresis",[16,20330,20331],{},"The sensor giving different outputs for the same input value depending on whether the input reached that value by increasing or decreasing.",[16,20333,20334,20336],{},[93,20335,19963],{}," In a pressure sensor:",[40,20338,20339,20342,20345],{},[43,20340,20341],{},"Rising to 50 psi → 2.50 V output",[43,20343,20344],{},"Falling to 50 psi → 2.48 V output",[43,20346,20347],{},"Hysteresis: 0.02 V (at 50 psi)",[29,20349,20351],{"className":751,"code":20350,"language":753,"meta":38,"style":38},"def calculate_hysteresis(rising_value, falling_value, full_scale):\n    \"\"\"Hysteresis calculation\"\"\"\n    hysteresis_absolute = abs(rising_value - falling_value)\n    hysteresis_percent = (hysteresis_absolute / full_scale) * 100\n    return hysteresis_percent\n\n# Example\nhyst = calculate_hysteresis(2.50, 2.48, 5.0)\nprint(f\"Hysteresis: {hyst:.2f}% FS\")\n# Output: Hysteresis: 0.40% FS\n",[36,20352,20353,20358,20363,20368,20373,20378,20382,20386,20391,20396],{"__ignoreMap":38},[270,20354,20355],{"class":272,"line":273},[270,20356,20357],{},"def calculate_hysteresis(rising_value, falling_value, full_scale):\n",[270,20359,20360],{"class":272,"line":279},[270,20361,20362],{},"    \"\"\"Hysteresis calculation\"\"\"\n",[270,20364,20365],{"class":272,"line":285},[270,20366,20367],{},"    hysteresis_absolute = abs(rising_value - falling_value)\n",[270,20369,20370],{"class":272,"line":291},[270,20371,20372],{},"    hysteresis_percent = (hysteresis_absolute / full_scale) * 100\n",[270,20374,20375],{"class":272,"line":297},[270,20376,20377],{},"    return hysteresis_percent\n",[270,20379,20380],{"class":272,"line":303},[270,20381,775],{"emptyLinePlaceholder":524},[270,20383,20384],{"class":272,"line":515},[270,20385,4838],{},[270,20387,20388],{"class":272,"line":793},[270,20389,20390],{},"hyst = calculate_hysteresis(2.50, 2.48, 5.0)\n",[270,20392,20393],{"class":272,"line":799},[270,20394,20395],{},"print(f\"Hysteresis: {hyst:.2f}% FS\")\n",[270,20397,20398],{"class":272,"line":805},[270,20399,20400],{},"# Output: Hysteresis: 0.40% FS\n",[24,20402,20404],{"id":20403},"_8-drift","8. Drift",[16,20406,20407],{},"The gradual change in the sensor's output over time despite constant conditions.",[16,20409,20410],{},[93,20411,20412],{},"Types of Drift:",[40,20414,20415,20421,20427],{},[43,20416,20417,20420],{},[93,20418,20419],{},"Zero Drift:"," Shift in zero point",[43,20422,20423,20426],{},[93,20424,20425],{},"Span Drift:"," Change in slope",[43,20428,20429,20432],{},[93,20430,20431],{},"Temperature Drift:"," Temperature-dependent drift (ppm/°C)",[16,20434,20435],{},[93,20436,20437],{},"Prevention Methods:",[40,20439,20440,20443,20446],{},[43,20441,20442],{},"Regular calibration",[43,20444,20445],{},"Temperature compensation",[43,20447,20448],{},"High-quality component selection",[24,20450,20452],{"id":20451},"_9-noise","9. Noise",[16,20454,20455],{},"Unwanted random signals in the sensor's output that do not originate from the measured physical quantity.",[16,20457,20458],{},[93,20459,20460],{},"Noise Sources:",[40,20462,20463,20466,20469,20472],{},[43,20464,20465],{},"Thermal noise (Johnson-Nyquist)",[43,20467,20468],{},"Shot noise",[43,20470,20471],{},"1/f noise (flicker noise)",[43,20473,20474],{},"Environmental interference (EMI/RFI)",[16,20476,20477],{},[93,20478,20479],{},"Signal-to-Noise Ratio (SNR):",[16,20481,20482],{},"SNR (dB) = 20 × log₁₀(V_signal / V_noise)",[29,20484,20486],{"className":751,"code":20485,"language":753,"meta":38,"style":38},"import numpy as np\n\n# SNR calculation\nsignal_amplitude = 10.0  # V\nnoise_rms = 0.001  # V\n\nsnr_ratio = signal_amplitude / noise_rms\nsnr_db = 20 * np.log10(snr_ratio)\nprint(f\"SNR: {snr_db:.1f} dB\")\n# Output: SNR: 80.0 dB\n",[36,20487,20488,20492,20496,20501,20506,20511,20515,20520,20525,20530],{"__ignoreMap":38},[270,20489,20490],{"class":272,"line":273},[270,20491,13988],{},[270,20493,20494],{"class":272,"line":279},[270,20495,775],{"emptyLinePlaceholder":524},[270,20497,20498],{"class":272,"line":285},[270,20499,20500],{},"# SNR calculation\n",[270,20502,20503],{"class":272,"line":291},[270,20504,20505],{},"signal_amplitude = 10.0  # V\n",[270,20507,20508],{"class":272,"line":297},[270,20509,20510],{},"noise_rms = 0.001  # V\n",[270,20512,20513],{"class":272,"line":303},[270,20514,775],{"emptyLinePlaceholder":524},[270,20516,20517],{"class":272,"line":515},[270,20518,20519],{},"snr_ratio = signal_amplitude / noise_rms\n",[270,20521,20522],{"class":272,"line":793},[270,20523,20524],{},"snr_db = 20 * np.log10(snr_ratio)\n",[270,20526,20527],{"class":272,"line":799},[270,20528,20529],{},"print(f\"SNR: {snr_db:.1f} dB\")\n",[270,20531,20532],{"class":272,"line":805},[270,20533,20534],{},"# Output: SNR: 80.0 dB\n",[16,20536,20537],{},[93,20538,20539],{},"Noise Reduction Techniques:",[40,20541,20542,20545,20548,20551],{},[43,20543,20544],{},"Digital filtering",[43,20546,20547],{},"Averaging",[43,20549,20550],{},"Shielding",[43,20552,20553],{},"Differential signal processing",[11,20555,20557],{"id":20556},"performance-in-zma-products","🎯 Performance in ZMA Products",[16,20559,20560],{},"These parameters are optimized as follows in our ZMA Data Acquisition system:",[636,20562,20563,20574],{},[639,20564,20565],{},[642,20566,20567,20570,20572],{},[645,20568,20569],{},"Parameter",[645,20571,650],{},[645,20573,8057],{},[655,20575,20576,20585,20596,20606,20617,20628],{},[642,20577,20578,20580,20582],{},[660,20579,2512],{},[660,20581,665],{},[660,20583,20584],{},"~0.6 µV @ 10V range",[642,20586,20587,20590,20593],{},[660,20588,20589],{},"Sensitivity",[660,20591,20592],{},"2-3 mV/V",[660,20594,20595],{},"Loadcell compatible",[642,20597,20598,20600,20603],{},[660,20599,1311],{},[660,20601,20602],{},"±0.05% FS",[660,20604,20605],{},"High accuracy",[642,20607,20608,20611,20614],{},[660,20609,20610],{},"Repeatability",[660,20612,20613],{},"±0.01% FS",[660,20615,20616],{},"Excellent precision",[642,20618,20619,20622,20625],{},[660,20620,20621],{},"Sampling Rate",[660,20623,20624],{},"1 kHz",[660,20626,20627],{},"Fast dynamic response",[642,20629,20630,20633,20636],{},[660,20631,20632],{},"Noise",[660,20634,20635],{},"\u003C1 µV RMS",[660,20637,20638],{},"Low noise",[11,20640,20642],{"id":20641},"practical-application-recommendations","💡 Practical Application Recommendations",[176,20644,20645,20661,20677,20690],{},[43,20646,20647,20650],{},[93,20648,20649],{},"Determine Application Requirements:",[40,20651,20652,20655,20658],{},[43,20653,20654],{},"What is the measurement range?",[43,20656,20657],{},"How much precision do you need?",[43,20659,20660],{},"How important is dynamic response?",[43,20662,20663,20666],{},[93,20664,20665],{},"Consider Environmental Factors:",[40,20667,20668,20671,20674],{},[43,20669,20670],{},"Operating temperature range",[43,20672,20673],{},"Humidity and vibration",[43,20675,20676],{},"EMI/RFI sources",[43,20678,20679,20682],{},[93,20680,20681],{},"Perform Regular Calibration:",[40,20683,20684,20687],{},[43,20685,20686],{},"Minimize drift effects",[43,20688,20689],{},"Maintain long-term accuracy",[43,20691,20692,20695],{},[93,20693,20694],{},"Use Signal Processing:",[40,20696,20697,20700],{},[43,20698,20699],{},"Reduce noise with filtering",[43,20701,20702],{},"Increase precision with averaging",[11,20704,444],{"id":443},[16,20706,20707],{},"Understanding sensor performance parameters correctly is fundamental to designing reliable measurement systems. Each application has different requirements, and understanding these terms will help you make the right sensor selection.",[17416,20709],{},[16,20711,20712],{},[3899,20713,20714,20715,20718],{},"Our ZMA products offer high performance and reliability in industrial applications. ",[463,20716,20717],{"href":1628},"Contact us"," for detailed technical information.",[477,20720,479],{},{"title":38,"searchDepth":279,"depth":279,"links":20722},[20723,20724,20730,20737,20738,20739],{"id":13,"depth":279,"text":14},{"id":19950,"depth":279,"text":19951,"children":20725},[20726,20727,20728,20729],{"id":19954,"depth":285,"text":19955},{"id":20008,"depth":285,"text":20009},{"id":20102,"depth":285,"text":20103},{"id":20128,"depth":285,"text":20129},{"id":20226,"depth":279,"text":20227,"children":20731},[20732,20733,20734,20735,20736],{"id":20230,"depth":285,"text":20231},{"id":20253,"depth":285,"text":20254},{"id":20327,"depth":285,"text":20328},{"id":20403,"depth":285,"text":20404},{"id":20451,"depth":285,"text":20452},{"id":20556,"depth":279,"text":20557},{"id":20641,"depth":279,"text":20642},{"id":443,"depth":279,"text":444},"Detailed examination of fundamental performance parameters such as resolution, sensitivity, accuracy, and repeatability in industrial sensors.",{"date":20742,"author":514,"readTime":805,"tags":20743},"2024-08-20",[20744,953,20745,2239],"Sensors","Instrumentation","/en/blog/sensor-performance-terminology",{"title":19940,"description":20740},"en/blog/sensor-performance-terminology","xSLpReB5WMdjwDUR8Z9ESurP4MIExAUJujsBzZcVSYU",{"id":20751,"title":20752,"body":20753,"description":21017,"extension":511,"meta":21018,"navigation":524,"path":21022,"seo":21023,"stem":21024,"__hash__":21025},"en_blog/en/blog/yocto-embedded-linux.md","Creating Custom Distributions with Yocto for Embedded Linux Systems",{"type":8,"value":20754,"toc":21007},[20755,20757,20760,20764,20767,20771,20796,20800,20803,20897,20901,20904,20920,20924,20927,20992,20994,20997,20999,21004],[11,20756,14],{"id":13},[16,20758,20759],{},"When developing embedded Linux systems, creating a customized and optimized operating system distribution is critically important. Yocto Project is a powerful tool that has become the industry standard for this purpose.",[11,20761,20763],{"id":20762},"what-is-yocto-project","What is Yocto Project?",[16,20765,20766],{},"Yocto Project is an open-source collaboration project used to create embedded Linux distributions. It is built on top of the BitBake build engine and OpenEmbedded layer architecture.",[24,20768,20770],{"id":20769},"key-advantages","Key Advantages",[40,20772,20773,20778,20784,20790],{},[43,20774,20775,20777],{},[93,20776,13233],{},": Minimal or full-featured systems tailored to your needs",[43,20779,20780,20783],{},[93,20781,20782],{},"Easy Maintenance",": Easy updates with layered architecture",[43,20785,20786,20789],{},[93,20787,20788],{},"Wide Hardware Support",": Works on various architectures",[43,20791,20792,20795],{},[93,20793,20794],{},"Community Support",": Active developer community",[11,20797,20799],{"id":20798},"getting-started","Getting Started",[16,20801,20802],{},"To start developing with Yocto, you first need to install the required tools:",[29,20804,20806],{"className":1993,"code":20805,"language":1995,"meta":38,"style":38},"sudo apt-get install gawk wget git diffstat unzip texinfo gcc build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev zstd liblz4-tool\n",[36,20807,20808],{"__ignoreMap":38},[270,20809,20810,20812,20814,20816,20819,20822,20825,20828,20831,20834,20837,20840,20843,20846,20849,20852,20855,20858,20861,20864,20867,20870,20873,20876,20879,20882,20885,20888,20891,20894],{"class":272,"line":273},[270,20811,2009],{"class":2008},[270,20813,2012],{"class":1930},[270,20815,2015],{"class":1930},[270,20817,20818],{"class":1930}," gawk",[270,20820,20821],{"class":1930}," wget",[270,20823,20824],{"class":1930}," git",[270,20826,20827],{"class":1930}," diffstat",[270,20829,20830],{"class":1930}," unzip",[270,20832,20833],{"class":1930}," texinfo",[270,20835,20836],{"class":1930}," gcc",[270,20838,20839],{"class":1930}," build-essential",[270,20841,20842],{"class":1930}," chrpath",[270,20844,20845],{"class":1930}," socat",[270,20847,20848],{"class":1930}," cpio",[270,20850,20851],{"class":1930}," python3",[270,20853,20854],{"class":1930}," python3-pip",[270,20856,20857],{"class":1930}," python3-pexpect",[270,20859,20860],{"class":1930}," xz-utils",[270,20862,20863],{"class":1930}," debianutils",[270,20865,20866],{"class":1930}," iputils-ping",[270,20868,20869],{"class":1930}," python3-git",[270,20871,20872],{"class":1930}," python3-jinja2",[270,20874,20875],{"class":1930}," libegl1-mesa",[270,20877,20878],{"class":1930}," libsdl1.2-dev",[270,20880,20881],{"class":1930}," pylint3",[270,20883,20884],{"class":1930}," xterm",[270,20886,20887],{"class":1930}," python3-subunit",[270,20889,20890],{"class":1930}," mesa-common-dev",[270,20892,20893],{"class":1930}," zstd",[270,20895,20896],{"class":1930}," liblz4-tool\n",[11,20898,20900],{"id":20899},"creating-layers","Creating Layers",[16,20902,20903],{},"To create your own layer:",[29,20905,20907],{"className":1993,"code":20906,"language":1995,"meta":38,"style":38},"bitbake-layers create-layer meta-mycompany\n",[36,20908,20909],{"__ignoreMap":38},[270,20910,20911,20914,20917],{"class":272,"line":273},[270,20912,20913],{"class":2008},"bitbake-layers",[270,20915,20916],{"class":1930}," create-layer",[270,20918,20919],{"class":1930}," meta-mycompany\n",[11,20921,20923],{"id":20922},"recipe-writing","Recipe Writing",[16,20925,20926],{},"Basic structure of an application recipe:",[29,20928,20930],{"className":751,"code":20929,"language":753,"meta":38,"style":38},"SUMMARY = \"My Custom Application\"\nLICENSE = \"MIT\"\nLIC_FILES_CHKSUM = \"file://LICENSE;md5=...\"\n\nSRC_URI = \"git://github.com/mycompany/myapp.git;protocol=https\"\nSRCREV = \"${AUTOREV}\"\n\ninherit cmake\n\ndo_install() {\n    install -d ${D}${bindir}\n    install -m 0755 myapp ${D}${bindir}\n}\n",[36,20931,20932,20937,20941,20946,20950,20955,20960,20964,20969,20973,20978,20983,20988],{"__ignoreMap":38},[270,20933,20934],{"class":272,"line":273},[270,20935,20936],{},"SUMMARY = \"My Custom Application\"\n",[270,20938,20939],{"class":272,"line":279},[270,20940,5404],{},[270,20942,20943],{"class":272,"line":285},[270,20944,20945],{},"LIC_FILES_CHKSUM = \"file://LICENSE;md5=...\"\n",[270,20947,20948],{"class":272,"line":291},[270,20949,775],{"emptyLinePlaceholder":524},[270,20951,20952],{"class":272,"line":297},[270,20953,20954],{},"SRC_URI = \"git://github.com/mycompany/myapp.git;protocol=https\"\n",[270,20956,20957],{"class":272,"line":303},[270,20958,20959],{},"SRCREV = \"${AUTOREV}\"\n",[270,20961,20962],{"class":272,"line":515},[270,20963,775],{"emptyLinePlaceholder":524},[270,20965,20966],{"class":272,"line":793},[270,20967,20968],{},"inherit cmake\n",[270,20970,20971],{"class":272,"line":799},[270,20972,775],{"emptyLinePlaceholder":524},[270,20974,20975],{"class":272,"line":805},[270,20976,20977],{},"do_install() {\n",[270,20979,20980],{"class":272,"line":2120},[270,20981,20982],{},"    install -d ${D}${bindir}\n",[270,20984,20985],{"class":272,"line":2126},[270,20986,20987],{},"    install -m 0755 myapp ${D}${bindir}\n",[270,20989,20990],{"class":272,"line":2132},[270,20991,2129],{},[11,20993,444],{"id":443},[16,20995,20996],{},"Yocto Project offers flexibility and control in embedded Linux development. When used correctly, it allows you to create easy-to-maintain and optimized systems.",[17416,20998],{},[16,21000,21001],{},[3899,21002,21003],{},"At Amazeng, we provide consulting and development services for embedded Linux systems. Contact us for your needs.",[477,21005,21006],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}",{"title":38,"searchDepth":279,"depth":279,"links":21008},[21009,21010,21013,21014,21015,21016],{"id":13,"depth":279,"text":14},{"id":20762,"depth":279,"text":20763,"children":21011},[21012],{"id":20769,"depth":285,"text":20770},{"id":20798,"depth":279,"text":20799},{"id":20899,"depth":279,"text":20900},{"id":20922,"depth":279,"text":20923},{"id":443,"depth":279,"text":444},"Learn how to create custom distributions for embedded Linux systems using Yocto Project, layer management, and recipe writing.",{"date":21019,"author":514,"readTime":793,"tags":21020},"2024-07-15",[522,2820,21021,2441],"Build Systems","/en/blog/yocto-embedded-linux",{"title":20752,"description":21017},"en/blog/yocto-embedded-linux","qk7SgVeRnX0KPKAwigrGnHCqXY9aF16ajSFLCNd5Axo",{"id":21027,"title":21028,"body":21029,"description":21281,"extension":511,"meta":21282,"navigation":524,"path":21286,"seo":21287,"stem":21288,"__hash__":21289},"en_blog/en/blog/modbus-protocol-integration.md","Modbus Protocol Integration in Industrial IoT Systems",{"type":8,"value":21030,"toc":21269},[21031,21035,21038,21042,21045,21048,21051,21054,21058,21061,21065,21068,21192,21196,21199,21225,21229,21255,21257,21260,21262,21267],[11,21032,21034],{"id":21033},"introduction-to-modbus-protocol","Introduction to Modbus Protocol",[16,21036,21037],{},"Modbus is one of the most widely used protocols in industrial automation systems, developed by Modicon (now Schneider Electric) in 1979 and still going strong today.",[11,21039,21041],{"id":21040},"modbus-variants","Modbus Variants",[24,21043,8020],{"id":21044},"modbus-rtu",[16,21046,21047],{},"Operates over RS485 or RS232 serial communication. Transmits data in binary format and uses CRC checksum.",[24,21049,687],{"id":21050},"modbus-tcp",[16,21052,21053],{},"Works over Ethernet networks via TCP/IP. Faster and more reliable than RTU.",[24,21055,21057],{"id":21056},"modbus-ascii","Modbus ASCII",[16,21059,21060],{},"Transmits data using ASCII characters over serial communication. Easier for debugging but slower than RTU.",[11,21062,21064],{"id":21063},"modbus-rtu-implementation-with-rs485","Modbus RTU Implementation with RS485",[16,21066,21067],{},"RS485-based Modbus implementation used in our ZMA Data Acquisition system:",[29,21069,21071],{"className":20037,"code":21070,"language":20039,"meta":38,"style":38},"#define MODBUS_SLAVE_ID 1\n#define BAUD_RATE 9600\n\ntypedef struct {\n    uint8_t slave_id;\n    uint8_t function_code;\n    uint16_t start_address;\n    uint16_t num_registers;\n    uint16_t crc;\n} modbus_request_t;\n\nuint16_t calculate_crc16(uint8_t *buffer, uint8_t length) {\n    uint16_t crc = 0xFFFF;\n    for (uint8_t i = 0; i \u003C length; i++) {\n        crc ^= buffer[i];\n        for (uint8_t j = 0; j \u003C 8; j++) {\n            if (crc & 0x0001) {\n                crc = (crc >> 1) ^ 0xA001;\n            } else {\n                crc >>= 1;\n            }\n        }\n    }\n    return crc;\n}\n",[36,21072,21073,21078,21083,21087,21092,21097,21102,21107,21112,21117,21122,21126,21131,21136,21141,21146,21151,21156,21161,21166,21171,21175,21179,21183,21188],{"__ignoreMap":38},[270,21074,21075],{"class":272,"line":273},[270,21076,21077],{},"#define MODBUS_SLAVE_ID 1\n",[270,21079,21080],{"class":272,"line":279},[270,21081,21082],{},"#define BAUD_RATE 9600\n",[270,21084,21085],{"class":272,"line":285},[270,21086,775],{"emptyLinePlaceholder":524},[270,21088,21089],{"class":272,"line":291},[270,21090,21091],{},"typedef struct {\n",[270,21093,21094],{"class":272,"line":297},[270,21095,21096],{},"    uint8_t slave_id;\n",[270,21098,21099],{"class":272,"line":303},[270,21100,21101],{},"    uint8_t function_code;\n",[270,21103,21104],{"class":272,"line":515},[270,21105,21106],{},"    uint16_t start_address;\n",[270,21108,21109],{"class":272,"line":793},[270,21110,21111],{},"    uint16_t num_registers;\n",[270,21113,21114],{"class":272,"line":799},[270,21115,21116],{},"    uint16_t crc;\n",[270,21118,21119],{"class":272,"line":805},[270,21120,21121],{},"} modbus_request_t;\n",[270,21123,21124],{"class":272,"line":2120},[270,21125,775],{"emptyLinePlaceholder":524},[270,21127,21128],{"class":272,"line":2126},[270,21129,21130],{},"uint16_t calculate_crc16(uint8_t *buffer, uint8_t length) {\n",[270,21132,21133],{"class":272,"line":2132},[270,21134,21135],{},"    uint16_t crc = 0xFFFF;\n",[270,21137,21138],{"class":272,"line":3375},[270,21139,21140],{},"    for (uint8_t i = 0; i \u003C length; i++) {\n",[270,21142,21143],{"class":272,"line":3381},[270,21144,21145],{},"        crc ^= buffer[i];\n",[270,21147,21148],{"class":272,"line":3387},[270,21149,21150],{},"        for (uint8_t j = 0; j \u003C 8; j++) {\n",[270,21152,21153],{"class":272,"line":3393},[270,21154,21155],{},"            if (crc & 0x0001) {\n",[270,21157,21158],{"class":272,"line":3399},[270,21159,21160],{},"                crc = (crc >> 1) ^ 0xA001;\n",[270,21162,21163],{"class":272,"line":3405},[270,21164,21165],{},"            } else {\n",[270,21167,21168],{"class":272,"line":3411},[270,21169,21170],{},"                crc >>= 1;\n",[270,21172,21173],{"class":272,"line":3417},[270,21174,4592],{},[270,21176,21177],{"class":272,"line":3423},[270,21178,4491],{},[270,21180,21181],{"class":272,"line":3429},[270,21182,3795],{},[270,21184,21185],{"class":272,"line":3434},[270,21186,21187],{},"    return crc;\n",[270,21189,21190],{"class":272,"line":3440},[270,21191,2129],{},[11,21193,21195],{"id":21194},"function-codes","Function Codes",[16,21197,21198],{},"Most commonly used Modbus function codes:",[40,21200,21201,21207,21213,21219],{},[43,21202,21203,21206],{},[93,21204,21205],{},"0x03",": Read Holding Registers",[43,21208,21209,21212],{},[93,21210,21211],{},"0x04",": Read Input Registers",[43,21214,21215,21218],{},[93,21216,21217],{},"0x06",": Write Single Register",[43,21220,21221,21224],{},[93,21222,21223],{},"0x10",": Write Multiple Registers",[11,21226,21228],{"id":21227},"practical-application-tips","Practical Application Tips",[176,21230,21231,21237,21243,21249],{},[43,21232,21233,21236],{},[93,21234,21235],{},"Timeout Management",": Set appropriate timeout values for each request",[43,21238,21239,21242],{},[93,21240,21241],{},"Error Handling",": Properly handle exception codes",[43,21244,21245,21248],{},[93,21246,21247],{},"Bus Termination",": Use 120Ω resistors at the beginning and end of RS485 line",[43,21250,21251,21254],{},[93,21252,21253],{},"Address Planning",": Keep slave device addresses organized",[11,21256,444],{"id":443},[16,21258,21259],{},"Modbus protocol continues to be preferred in industrial systems due to its simplicity and reliability. It can also work with modern systems through bridge solutions in IoT integration.",[17416,21261],{},[16,21263,21264],{},[3899,21265,21266],{},"Our ZMA Data Acquisition system easily integrates into your industrial systems with Modbus RTU support. Contact us for detailed information.",[477,21268,479],{},{"title":38,"searchDepth":279,"depth":279,"links":21270},[21271,21272,21277,21278,21279,21280],{"id":21033,"depth":279,"text":21034},{"id":21040,"depth":279,"text":21041,"children":21273},[21274,21275,21276],{"id":21044,"depth":285,"text":8020},{"id":21050,"depth":285,"text":687},{"id":21056,"depth":285,"text":21057},{"id":21063,"depth":279,"text":21064},{"id":21194,"depth":279,"text":21195},{"id":21227,"depth":279,"text":21228},{"id":443,"depth":279,"text":444},"Learn how to integrate the widely used Modbus protocol in industrial automation systems into IoT devices.",{"date":21283,"author":514,"readTime":303,"tags":21284},"2024-06-10",[10216,2441,21285,17712],"RS485","/en/blog/modbus-protocol-integration",{"title":21028,"description":21281},"en/blog/modbus-protocol-integration","kfT9DkLAs7EP5Dt7P5zaQbWhNdwIqZTXhkWb5va2Jcc",{"id":21291,"title":21292,"body":21293,"description":21681,"extension":511,"meta":21682,"navigation":524,"path":21687,"seo":21688,"stem":21689,"__hash__":21690},"en_blog/en/blog/high-precision-adc-selection.md","High Precision ADC Selection and Applications",{"type":8,"value":21294,"toc":21661},[21295,21299,21302,21306,21310,21313,21327,21330,21333,21339,21343,21347,21350,21356,21360,21363,21382,21386,21389,21477,21481,21484,21490,21494,21498,21546,21550,21584,21588,21614,21618,21621,21647,21649,21652,21654,21659],[11,21296,21298],{"id":21297},"importance-of-adc-in-precision-measurement","Importance of ADC in Precision Measurement",[16,21300,21301],{},"In industrial measurement systems, choosing the right ADC (Analog-Digital Converter) directly affects system performance. 24-bit resolution offers the ability to measure at the microVolt level.",[11,21303,21305],{"id":21304},"adc-performance-criteria","ADC Performance Criteria",[24,21307,21309],{"id":21308},"resolution-vs-effective-number-of-bits-enob","Resolution vs. Effective Number of Bits (ENOB)",[16,21311,21312],{},"The difference between theoretical resolution and actual performance is critical:",[40,21314,21315,21321],{},[43,21316,21317,21320],{},[93,21318,21319],{},"24-bit resolution",": 16,777,216 discrete levels",[43,21322,21323,21326],{},[93,21324,21325],{},"ENOB",": Effective resolution reduced by noise and distortion",[24,21328,20621],{"id":21329},"sampling-rate",[16,21331,21332],{},"Typically 1kHz sampling rate is used in industrial applications:",[29,21334,21337],{"className":21335,"code":21336,"language":34},[32],"f_sample = 1kHz\nT_sample = 1ms\nNyquist Frequency = 500Hz\n",[36,21338,21336],{"__ignoreMap":38},[11,21340,21342],{"id":21341},"signal-conditioning","Signal Conditioning",[24,21344,21346],{"id":21345},"anti-aliasing-filter","Anti-Aliasing Filter",[16,21348,21349],{},"Analog filtering before sampling is mandatory:",[29,21351,21354],{"className":21352,"code":21353,"language":34},[32],"f_cutoff = 0.4 * f_sample = 400Hz (for 1kHz)\nFilter Order: 4th order Butterworth\n",[36,21355,21353],{"__ignoreMap":38},[24,21357,21359],{"id":21358},"reference-voltage-stability","Reference Voltage Stability",[16,21361,21362],{},"Ultra-low drift reference for precision measurements:",[40,21364,21365,21371,21376],{},[43,21366,21367,21370],{},[93,21368,21369],{},"Drift",": \u003C 2ppm/°C",[43,21372,21373,21375],{},[93,21374,20632],{},": \u003C 10µVrms",[43,21377,21378,21381],{},[93,21379,21380],{},"Long-term stability",": \u003C 50ppm/1000hr",[11,21383,21385],{"id":21384},"loadcell-application","Loadcell Application",[16,21387,21388],{},"Example 2mV/V loadcell reading circuit commonly used in industrial weighing systems:",[29,21390,21392],{"className":20037,"code":21391,"language":20039,"meta":38,"style":38},"// 10V excitation, 2mV/V loadcell\n// Full scale: 20mV\n// 24-bit ADC: 2.5V reference\n// Gain: 2.5V / 20mV = 125\n\n#define ADC_REF_VOLTAGE 2.5\n#define LOADCELL_SENSITIVITY 2.0  // mV/V\n#define EXCITATION_VOLTAGE 10.0   // V\n#define PGA_GAIN 125\n\nfloat calculate_weight(uint32_t adc_value) {\n    float voltage = (adc_value / 16777216.0) * ADC_REF_VOLTAGE;\n    float loadcell_mv = (voltage / PGA_GAIN) * 1000;\n    float weight_kg = loadcell_mv / (LOADCELL_SENSITIVITY * EXCITATION_VOLTAGE);\n    return weight_kg * calibration_factor;\n}\n",[36,21393,21394,21399,21404,21409,21414,21418,21423,21431,21439,21444,21448,21453,21458,21463,21468,21473],{"__ignoreMap":38},[270,21395,21396],{"class":272,"line":273},[270,21397,21398],{},"// 10V excitation, 2mV/V loadcell\n",[270,21400,21401],{"class":272,"line":279},[270,21402,21403],{},"// Full scale: 20mV\n",[270,21405,21406],{"class":272,"line":285},[270,21407,21408],{},"// 24-bit ADC: 2.5V reference\n",[270,21410,21411],{"class":272,"line":291},[270,21412,21413],{},"// Gain: 2.5V / 20mV = 125\n",[270,21415,21416],{"class":272,"line":297},[270,21417,775],{"emptyLinePlaceholder":524},[270,21419,21420],{"class":272,"line":303},[270,21421,21422],{},"#define ADC_REF_VOLTAGE 2.5\n",[270,21424,21425,21428],{"class":272,"line":515},[270,21426,21427],{},"#define LOADCELL_SENSITIVITY 2.0",[270,21429,21430],{},"  // mV/V\n",[270,21432,21433,21436],{"class":272,"line":793},[270,21434,21435],{},"#define EXCITATION_VOLTAGE 10.0",[270,21437,21438],{},"   // V\n",[270,21440,21441],{"class":272,"line":799},[270,21442,21443],{},"#define PGA_GAIN 125\n",[270,21445,21446],{"class":272,"line":805},[270,21447,775],{"emptyLinePlaceholder":524},[270,21449,21450],{"class":272,"line":2120},[270,21451,21452],{},"float calculate_weight(uint32_t adc_value) {\n",[270,21454,21455],{"class":272,"line":2126},[270,21456,21457],{},"    float voltage = (adc_value / 16777216.0) * ADC_REF_VOLTAGE;\n",[270,21459,21460],{"class":272,"line":2132},[270,21461,21462],{},"    float loadcell_mv = (voltage / PGA_GAIN) * 1000;\n",[270,21464,21465],{"class":272,"line":3375},[270,21466,21467],{},"    float weight_kg = loadcell_mv / (LOADCELL_SENSITIVITY * EXCITATION_VOLTAGE);\n",[270,21469,21470],{"class":272,"line":3381},[270,21471,21472],{},"    return weight_kg * calibration_factor;\n",[270,21474,21475],{"class":272,"line":3387},[270,21476,2129],{},[11,21478,21480],{"id":21479},"_4-20ma-current-loop-reading","4-20mA Current Loop Reading",[16,21482,21483],{},"Industrial sensor standard:",[29,21485,21488],{"className":21486,"code":21487,"language":34},[32],"I_min = 4mA  → Sensor minimum\nI_max = 20mA → Sensor maximum\nR_shunt = 250Ω\n\nV_min = 4mA × 250Ω = 1V\nV_max = 20mA × 250Ω = 5V\n",[36,21489,21487],{"__ignoreMap":38},[11,21491,21493],{"id":21492},"calibration-and-linearization","Calibration and Linearization",[24,21495,21497],{"id":21496},"two-point-calibration","Two-Point Calibration",[29,21499,21501],{"className":751,"code":21500,"language":753,"meta":38,"style":38},"# Zero calibration\nzero_reading = adc.read()\n\n# Span calibration (known weight)\nspan_reading = adc.read()\nspan_weight = 10.0  # kg\n\ngain = span_weight / (span_reading - zero_reading)\noffset = -zero_reading * gain\n",[36,21502,21503,21508,21513,21517,21522,21527,21532,21536,21541],{"__ignoreMap":38},[270,21504,21505],{"class":272,"line":273},[270,21506,21507],{},"# Zero calibration\n",[270,21509,21510],{"class":272,"line":279},[270,21511,21512],{},"zero_reading = adc.read()\n",[270,21514,21515],{"class":272,"line":285},[270,21516,775],{"emptyLinePlaceholder":524},[270,21518,21519],{"class":272,"line":291},[270,21520,21521],{},"# Span calibration (known weight)\n",[270,21523,21524],{"class":272,"line":297},[270,21525,21526],{},"span_reading = adc.read()\n",[270,21528,21529],{"class":272,"line":303},[270,21530,21531],{},"span_weight = 10.0  # kg\n",[270,21533,21534],{"class":272,"line":515},[270,21535,775],{"emptyLinePlaceholder":524},[270,21537,21538],{"class":272,"line":793},[270,21539,21540],{},"gain = span_weight / (span_reading - zero_reading)\n",[270,21542,21543],{"class":272,"line":799},[270,21544,21545],{},"offset = -zero_reading * gain\n",[24,21547,21549],{"id":21548},"temperature-compensation","Temperature Compensation",[29,21551,21553],{"className":20037,"code":21552,"language":20039,"meta":38,"style":38},"float temp_coefficient = -0.002;  // %/°C\nfloat reference_temp = 25.0;      // °C\nfloat current_temp = read_temperature();\n\nfloat temp_correction = 1.0 + temp_coefficient * (current_temp - reference_temp);\nfloat corrected_value = raw_value * temp_correction;\n",[36,21554,21555,21560,21565,21570,21574,21579],{"__ignoreMap":38},[270,21556,21557],{"class":272,"line":273},[270,21558,21559],{},"float temp_coefficient = -0.002;  // %/°C\n",[270,21561,21562],{"class":272,"line":279},[270,21563,21564],{},"float reference_temp = 25.0;      // °C\n",[270,21566,21567],{"class":272,"line":285},[270,21568,21569],{},"float current_temp = read_temperature();\n",[270,21571,21572],{"class":272,"line":291},[270,21573,775],{"emptyLinePlaceholder":524},[270,21575,21576],{"class":272,"line":297},[270,21577,21578],{},"float temp_correction = 1.0 + temp_coefficient * (current_temp - reference_temp);\n",[270,21580,21581],{"class":272,"line":303},[270,21582,21583],{},"float corrected_value = raw_value * temp_correction;\n",[11,21585,21587],{"id":21586},"pcb-layout-recommendations","PCB Layout Recommendations",[176,21589,21590,21596,21602,21608],{},[43,21591,21592,21595],{},[93,21593,21594],{},"Analog Ground Plane",": Separate from digital, single point connection",[43,21597,21598,21601],{},[93,21599,21600],{},"Kelvin Connection",": For 4-wire measurement",[43,21603,21604,21607],{},[93,21605,21606],{},"Guard Rings",": Preventing leakage currents",[43,21609,21610,21613],{},[93,21611,21612],{},"Component Placement",": Reference and filter components close to ADC",[11,21615,21617],{"id":21616},"emiemc-protection","EMI/EMC Protection",[16,21619,21620],{},"EMI protection is critical in industrial environments:",[40,21622,21623,21629,21635,21641],{},[43,21624,21625,21628],{},[93,21626,21627],{},"Differential Input",": Common mode noise suppression",[43,21630,21631,21634],{},[93,21632,21633],{},"RC Filtering",": 1kΩ + 100nF at ADC input",[43,21636,21637,21640],{},[93,21638,21639],{},"Shielded Cable",": Twisted pair, shield grounded",[43,21642,21643,21646],{},[93,21644,21645],{},"Ferrite Beads",": At power inputs",[11,21648,444],{"id":443},[16,21650,21651],{},"High precision ADC selection and implementation requires careful design and calibration. By applying these principles, industry-standard precision can be achieved.",[17416,21653],{},[16,21655,21656],{},[3899,21657,21658],{},"With over 10 years of experience in precision measurement systems design, Amazeng offers customized solutions for you.",[477,21660,479],{},{"title":38,"searchDepth":279,"depth":279,"links":21662},[21663,21664,21668,21672,21673,21674,21678,21679,21680],{"id":21297,"depth":279,"text":21298},{"id":21304,"depth":279,"text":21305,"children":21665},[21666,21667],{"id":21308,"depth":285,"text":21309},{"id":21329,"depth":285,"text":20621},{"id":21341,"depth":279,"text":21342,"children":21669},[21670,21671],{"id":21345,"depth":285,"text":21346},{"id":21358,"depth":285,"text":21359},{"id":21384,"depth":279,"text":21385},{"id":21479,"depth":279,"text":21480},{"id":21492,"depth":279,"text":21493,"children":21675},[21676,21677],{"id":21496,"depth":285,"text":21497},{"id":21548,"depth":285,"text":21549},{"id":21586,"depth":279,"text":21587},{"id":21616,"depth":279,"text":21617},{"id":443,"depth":279,"text":444},"Detailed guide on the use of 24-bit ADC solutions in industrial measurement systems, calibration, and performance optimization.",{"date":21683,"author":514,"readTime":805,"tags":21684},"2024-01-05",[662,21685,953,20744,21686],"Analog","PCB Design","/en/blog/high-precision-adc-selection",{"title":21292,"description":21681},"en/blog/high-precision-adc-selection","GhEo_eQz_ml99FiLxl8SZpcHsB0713BiQLv8xiir2oI",1778229653598]