<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Suraj Informatics</title>
    <description>The latest articles on DEV Community by Suraj Informatics (@suraj_informatics).</description>
    <link>https://dev.to/suraj_informatics</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4147639%2F0ebf69dd-3b29-4943-ba47-01ed6763ff12.png</url>
      <title>DEV Community: Suraj Informatics</title>
      <link>https://dev.to/suraj_informatics</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suraj_informatics"/>
    <language>en</language>
    <item>
      <title>Designing the Data Model Behind a Turnstile Access Control System</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Wed, 21 Oct 2026 12:25:19 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/designing-the-data-model-behind-a-turnstile-access-control-system-10ak</link>
      <guid>https://dev.to/suraj_informatics/designing-the-data-model-behind-a-turnstile-access-control-system-10ak</guid>
      <description>&lt;p&gt;A turnstile looks like hardware, but most of the engineering sits behind it. If you are integrating readers and barriers into a gate platform, the data model decides whether the first week is smooth or full of denied entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision the controller must make
&lt;/h2&gt;

&lt;p&gt;When someone presents a credential, the controller has roughly a second to answer one question: open or stay locked. That needs three lookups.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity:&lt;/strong&gt; does this credential map to an active person?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy:&lt;/strong&gt; is this person allowed at this gate, in this zone, at this time?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State:&lt;/strong&gt; are they already inside (anti-passback), or has the pass expired?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A minimal schema
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gate_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shift_start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shift_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gate_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;event&lt;/code&gt; append-only. Denied attempts are as valuable as granted ones, because they expose data errors and misplaced readers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline first
&lt;/h2&gt;

&lt;p&gt;Gate hardware should keep a local copy of the allow-list and keep deciding when the network drops. Queue events locally and sync later. A turnstile that waits for a server on every read will fail on the first bad connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fail-safe is not optional
&lt;/h2&gt;

&lt;p&gt;Treat fire alarm and power loss as hard inputs that release the barrier regardless of software state. Test this during commissioning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics worth tracking
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Read success rate per reader&lt;/li&gt;
&lt;li&gt;Average passage time at peak&lt;/li&gt;
&lt;li&gt;Denials per hundred reads, split by reason&lt;/li&gt;
&lt;li&gt;Tailgating alerts, if you use presence sensors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the physical side, barrier types and a rollout plan, see the &lt;a href="https://www.surajinformatics.com/2026/10/21/turnstile-access-control-system-control-entry-log-every-pass/" rel="noopener noreferrer"&gt;turnstile access control system guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>security</category>
      <category>architecture</category>
      <category>embedded</category>
    </item>
    <item>
      <title>Designing Room-Level Location Logic for a Hospital RTLS</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Fri, 16 Oct 2026 11:15:24 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/designing-room-level-location-logic-for-a-hospital-rtls-1h9e</link>
      <guid>https://dev.to/suraj_informatics/designing-room-level-location-logic-for-a-hospital-rtls-1h9e</guid>
      <description>&lt;p&gt;BLE beacons and RFID readers in a hospital do not tell you "the pump is in room 304". They tell you that tag &lt;code&gt;A1F3&lt;/code&gt; was heard by receiver &lt;code&gt;R-3-07&lt;/code&gt; at -71 dBm. Turning that stream into a reliable room-level location is the core software problem in any hospital RTLS.&lt;/p&gt;

&lt;h2&gt;
  
  
  The raw data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sighting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tag_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;        &lt;span class="c1"&gt;# tag on the device
&lt;/span&gt;    &lt;span class="n"&gt;receiver_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;   &lt;span class="c1"&gt;# fixed receiver, mapped to a room or zone
&lt;/span&gt;    &lt;span class="n"&gt;rssi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;          &lt;span class="c1"&gt;# signal strength in dBm
&lt;/span&gt;    &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: smooth the noise
&lt;/h2&gt;

&lt;p&gt;RSSI jumps around as people walk past and doors open. Never decide location from a single reading. Keep a short window per tag and receiver and use the median:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;median&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;

&lt;span class="n"&gt;WINDOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxlen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sighting&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiver_id&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rssi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;strength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vals&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: pick a room, with hysteresis
&lt;/h2&gt;

&lt;p&gt;Choose the receiver with the strongest smoothed signal, but only move the device to a new room if the new room wins by a margin for a few cycles. Without this, a pump near a wall will "flicker" between two rooms all day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MARGIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;   &lt;span class="c1"&gt;# dB the new room must win by
&lt;/span&gt;&lt;span class="n"&gt;CONFIRM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;  &lt;span class="c1"&gt;# consecutive cycles
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;streak&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;best_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best_room&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;current_room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MARGIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;streak&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;streak&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;CONFIRM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current_room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;streak&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: handle silence
&lt;/h2&gt;

&lt;p&gt;Tags go quiet when batteries die, when a device is in a shielded room, or when it has left the building. Store a &lt;code&gt;last_seen&lt;/code&gt; time and show "last seen in ICU, 2 hours ago" instead of pretending the location is current. Alert when a high-value device goes silent near an exit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from the field
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Map every receiver to a room in a config table, not in code. Rooms get renumbered.&lt;/li&gt;
&lt;li&gt;Log raw sightings for a week before tuning &lt;code&gt;MARGIN&lt;/code&gt; and &lt;code&gt;CONFIRM&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Room-level accuracy needs enough receivers; software cannot fix a receiver that hears three rooms equally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the business side (which equipment to tag first, maintenance and audit benefits), see this guide to the &lt;a href="https://www.surajinformatics.com/2026/10/16/hospital-asset-tracking-system-find-any-device-in-seconds/" rel="noopener noreferrer"&gt;hospital asset tracking system&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>rtls</category>
      <category>healthcare</category>
      <category>python</category>
    </item>
    <item>
      <title>Designing a Plate Reading Pipeline for Truck Gates: Events, Confidence and Fallbacks</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Tue, 13 Oct 2026 06:30:30 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/designing-a-plate-reading-pipeline-for-truck-gates-events-confidence-and-fallbacks-4p6m</link>
      <guid>https://dev.to/suraj_informatics/designing-a-plate-reading-pipeline-for-truck-gates-events-confidence-and-fallbacks-4p6m</guid>
      <description>&lt;p&gt;If you are building or integrating plate reading at an industrial gate, the camera and the model are the easy part. The hard part is turning noisy reads into reliable events that the rest of your gate system can trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  One read, one event
&lt;/h2&gt;

&lt;p&gt;Treat every read as an immutable event, not a database row you keep updating. A minimal shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gate2-in-20261013T061244-0187"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lane"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gate-2-in"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plate_raw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MH43 AB 1234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plate_norm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MH43AB1234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.91&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image_ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"images/gate2/0187.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"captured_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-13T06:12:44Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the raw string and the normalised one. When a dispute comes up, the raw read and the image are your evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalise before you match
&lt;/h2&gt;

&lt;p&gt;Strip spaces and separators, force upper case, and handle the classic confusions: O and 0, I and 1, B and 8. Validate against the plate formats you expect, such as Indian state formats or Gulf formats, but do not reject a read just because it fails validation. Route it for review instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use confidence as a routing rule
&lt;/h2&gt;

&lt;p&gt;A single threshold is too blunt. Three bands work better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High:&lt;/strong&gt; match to the booked trip and open the barrier automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium:&lt;/strong&gt; show the guard the image and the best match, and let them confirm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low:&lt;/strong&gt; ask for manual entry and store it as an override with a user ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tune the bands on a week of your own lane data, not on vendor samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deduplicate bursts
&lt;/h2&gt;

&lt;p&gt;A truck that stops under the camera can produce several reads. Collapse reads of the same normalised plate in the same lane inside a short window, and keep the highest-confidence image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fail soft
&lt;/h2&gt;

&lt;p&gt;Gates cannot stop because a network link dropped. Buffer events at the edge, give each one a stable &lt;code&gt;event_id&lt;/code&gt;, and make the server side idempotent so a replay never creates a second trip record.&lt;/p&gt;

&lt;p&gt;For the business side, including where plant and port gates use this and what to test in a trial, see the full guide: &lt;a href="https://www.surajinformatics.com/2026/10/13/number-plate-recognition-guide/" rel="noopener noreferrer"&gt;number plate recognition for plant and port gates&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>anpr</category>
      <category>computervision</category>
      <category>iot</category>
      <category>logistics</category>
    </item>
    <item>
      <title>Building Fleet Tracking for Industrial Sites: Events, Geofences and Data Joins</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Wed, 07 Oct 2026 16:40:15 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/building-fleet-tracking-for-industrial-sites-events-geofences-and-data-joins-393n</link>
      <guid>https://dev.to/suraj_informatics/building-fleet-tracking-for-industrial-sites-events-geofences-and-data-joins-393n</guid>
      <description>&lt;p&gt;Fleet tracking looks simple from the outside: put a GPS device in a truck and draw dots on a map. In industrial environments, the interesting engineering starts after the dot appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events, not just coordinates
&lt;/h2&gt;

&lt;p&gt;A plant or port cares less about latitude and longitude and more about &lt;strong&gt;events&lt;/strong&gt;: vehicle entered gate 2, stopped at weighbridge 1, idled 18 minutes at bay 4, exited at 14:32. Turning raw GPS pings into these events means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defining &lt;strong&gt;geofences&lt;/strong&gt; as polygons around gates, weighbridges and bays,&lt;/li&gt;
&lt;li&gt;handling &lt;strong&gt;GPS drift&lt;/strong&gt; (a stationary truck can "move" a few metres every minute),&lt;/li&gt;
&lt;li&gt;debouncing entry/exit so one wobble at a fence line does not create ten events.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Joining data from different systems
&lt;/h2&gt;

&lt;p&gt;Fleet data becomes useful when it is joined with other sources:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;What it adds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPS tracker&lt;/td&gt;
&lt;td&gt;device ID + time&lt;/td&gt;
&lt;td&gt;position, speed, ignition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fuel dispenser&lt;/td&gt;
&lt;td&gt;vehicle ID + time&lt;/td&gt;
&lt;td&gt;litres issued&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weighbridge&lt;/td&gt;
&lt;td&gt;number plate + time&lt;/td&gt;
&lt;td&gt;gross and tare weight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gate ANPR&lt;/td&gt;
&lt;td&gt;number plate + time&lt;/td&gt;
&lt;td&gt;entry and exit stamps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The hard part is &lt;strong&gt;identity&lt;/strong&gt;: the tracker knows a device ID, the gate camera knows a plate, the dispenser knows an RFID tag. A clean vehicle master table that maps all three is the backbone of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful derived metrics
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fuel_per_km      = litres_issued / km_driven
idle_ratio       = idle_minutes / ignition_on_minutes
site_turnaround  = exit_time - entry_time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Outliers in these three numbers explain most fleet cost problems on industrial sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alerts that people act on
&lt;/h2&gt;

&lt;p&gt;Too many alerts and supervisors ignore them all. Start with three: long idling inside the site, fuel-per-km above the vehicle's own average, and overdue maintenance. Tune thresholds during a pilot before scaling.&lt;/p&gt;

&lt;p&gt;For the operational side of this, covering features, weekly KPIs and a rollout plan, read this &lt;a href="https://www.surajinformatics.com/2026/10/07/vehicle-fleet-management/" rel="noopener noreferrer"&gt;guide to vehicle fleet management for plants and ports&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>logistics</category>
      <category>dataengineering</category>
      <category>gps</category>
    </item>
    <item>
      <title>Building the Data Flow Behind an Unmanned Weighbridge</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Sun, 04 Oct 2026 17:15:15 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/building-the-data-flow-behind-an-unmanned-weighbridge-4oec</link>
      <guid>https://dev.to/suraj_informatics/building-the-data-flow-behind-an-unmanned-weighbridge-4oec</guid>
      <description>&lt;p&gt;An unmanned weighbridge looks like a hardware project: load cells, cameras, an RFID reader, a boom barrier. In practice most of the work is software, and specifically one question: &lt;strong&gt;when is a weighment valid?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The event sequence
&lt;/h2&gt;

&lt;p&gt;A single weighment is a small state machine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;VEHICLE_DETECTED&lt;/code&gt;: RFID read or number-plate match&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POSITION_OK&lt;/code&gt;: platform sensors confirm all axles are on the scale&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WEIGHT_STABLE&lt;/code&gt;: the indicator reports a stable value for N readings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EVIDENCE_CAPTURED&lt;/code&gt;: camera snapshots stored with the transaction ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TRANSACTION_CLOSED&lt;/code&gt;: slip issued, barrier opened, record sent onward&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any state fails or times out, the transaction moves to &lt;code&gt;EXCEPTION&lt;/code&gt; and a supervisor is alerted. Nothing is silently accepted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the indicator
&lt;/h2&gt;

&lt;p&gt;Most weight indicators push a continuous string over RS-232 or TCP. The terminal parses it, checks the stability flag and keeps a short rolling window. The key design rule: &lt;strong&gt;the weight value never passes through a user-editable field.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotent ERP posting
&lt;/h2&gt;

&lt;p&gt;The weighment is posted to the ERP (often SAP) with the transaction ID as the key. If the network drops, the terminal retries, and the ERP rejects duplicates. This avoids the classic double goods-receipt problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence storage
&lt;/h2&gt;

&lt;p&gt;Photos are stored against the transaction ID with the time stamp and gross, tare and net weights. When someone disputes a weight months later, a single lookup returns everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling exceptions
&lt;/h2&gt;

&lt;p&gt;The exception path deserves as much design as the happy path. Typical cases: unknown RFID tag, plate read with low confidence, weight outside the order tolerance, or a camera offline. Each case gets a clear rule: hold the barrier, alert a supervisor, or allow with a flag. Log the decision and who made it, so audits can follow the trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline mode
&lt;/h2&gt;

&lt;p&gt;Plants lose network more often than anyone admits. The terminal should keep a local queue of transactions and evidence, continue weighing under the same rules, and sync when the link returns, using the same idempotent keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;Each terminal sends a heartbeat. A dashboard shows queue length, average platform time and exception counts per site, which is where truck turnaround improvements actually become visible.&lt;/p&gt;

&lt;p&gt;We wrote a non-technical overview of the same system for plant and port managers. It covers features and rollout planning: &lt;a href="https://www.surajinformatics.com/2026/10/04/intelligent-terminal-for-weighbridges/" rel="noopener noreferrer"&gt;intelligent terminal for weighbridges&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>automation</category>
      <category>logistics</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Validating Container Numbers from Gate OCR with the ISO 6346 Check Digit</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Sun, 04 Oct 2026 10:16:52 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/validating-container-numbers-from-gate-ocr-with-the-iso-6346-check-digit-1g8</link>
      <guid>https://dev.to/suraj_informatics/validating-container-numbers-from-gate-ocr-with-the-iso-6346-check-digit-1g8</guid>
      <description>&lt;p&gt;Container depots and terminals increasingly read container numbers with OCR cameras at the gate. OCR is fast, but it is not perfect: a smudged &lt;code&gt;8&lt;/code&gt; becomes a &lt;code&gt;B&lt;/code&gt;, a &lt;code&gt;0&lt;/code&gt; becomes an &lt;code&gt;O&lt;/code&gt;. The good news is that every shipping container number carries its own error check, defined in &lt;strong&gt;ISO 6346&lt;/strong&gt;. You can catch most misreads with a few lines of code before they reach your yard system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a container number
&lt;/h2&gt;

&lt;p&gt;A container number like &lt;code&gt;CSQU3054383&lt;/code&gt; has four parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CSQ&lt;/code&gt; - the owner code (3 letters)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U&lt;/code&gt; - the equipment category (&lt;code&gt;U&lt;/code&gt; for freight containers)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;305438&lt;/code&gt; - the serial number (6 digits)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt; - the check digit&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How the check digit works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Give each letter a value starting at A = 10, skipping multiples of 11 (so 11, 22 and 33 are never used). Digits keep their own value.&lt;/li&gt;
&lt;li&gt;Multiply each of the first 10 characters by 2 to the power of its position (1, 2, 4, 8 ... 512).&lt;/li&gt;
&lt;li&gt;Add the results, take the remainder after dividing by 11, then take the last digit (a remainder of 10 becomes 0).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;letter_values&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;

&lt;span class="n"&gt;VALUES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;letter_values&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^[A-Z]{3}[UJZ][0-9]{7}$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_digit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isalpha&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PATTERN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;check_digit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CSQU3054383&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CSQU3054388&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# False - OCR misread
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using it at the gate
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reject or flag&lt;/strong&gt; any OCR reading that fails the check, and ask the gate clerk to confirm only those trucks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try likely swaps&lt;/strong&gt; (&lt;code&gt;O&lt;/code&gt;/&lt;code&gt;0&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;/&lt;code&gt;8&lt;/code&gt;, &lt;code&gt;I&lt;/code&gt;/&lt;code&gt;1&lt;/code&gt;) on a failed read and accept a candidate only if exactly one passes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log both&lt;/strong&gt; the raw OCR text and the corrected number, so you can measure camera accuracy over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This small check turns OCR from "usually right" into something a yard system can trust, which is what makes truly automated gates possible at depots and terminals.&lt;/p&gt;

&lt;p&gt;For the bigger picture of how gates, weighbridges, yards and rail sidings work together at an inland depot, see this guide to the &lt;a href="https://www.surajinformatics.com/2026/10/04/inland-container-depot-icd-what-it-is-how-it-works-and-where-automation-cuts-delays/" rel="noopener noreferrer"&gt;inland container depot (ICD)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>logistics</category>
      <category>iot</category>
      <category>automation</category>
    </item>
    <item>
      <title>Modelling Truck Flow Through a Container Terminal as Events</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Sat, 03 Oct 2026 10:37:26 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/modelling-truck-flow-through-a-container-terminal-as-events-58ie</link>
      <guid>https://dev.to/suraj_informatics/modelling-truck-flow-through-a-container-terminal-as-events-58ie</guid>
      <description>&lt;p&gt;Container terminals are a good example of a system where the interesting data is not the state but the &lt;strong&gt;events&lt;/strong&gt;. A truck enters the gate, gets weighed, picks up a box in the yard and leaves. If each of those moments is recorded as an event, almost every operational question becomes a simple query.&lt;/p&gt;

&lt;h2&gt;
  
  
  The events
&lt;/h2&gt;

&lt;p&gt;A minimal event table for the land side of a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;truck_events&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;          &lt;span class="nb"&gt;BIGINT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;visit_id&lt;/span&gt;    &lt;span class="nb"&gt;BIGINT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;-- one truck visit&lt;/span&gt;
  &lt;span class="n"&gt;vehicle_no&lt;/span&gt;  &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;-- read by ANPR&lt;/span&gt;
  &lt;span class="n"&gt;container&lt;/span&gt;   &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;          &lt;span class="c1"&gt;-- read by OCR, ISO 6346 format&lt;/span&gt;
  &lt;span class="n"&gt;event_type&lt;/span&gt;  &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;-- GATE_IN, WEIGH_1, YARD_PICK, WEIGH_2, GATE_OUT&lt;/span&gt;
  &lt;span class="k"&gt;location&lt;/span&gt;    &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;          &lt;span class="c1"&gt;-- gate lane, weighbridge id, yard block&lt;/span&gt;
  &lt;span class="n"&gt;created_at&lt;/span&gt;  &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Questions it answers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Truck turnaround time:&lt;/strong&gt; &lt;code&gt;GATE_OUT&lt;/code&gt; minus &lt;code&gt;GATE_IN&lt;/code&gt; per &lt;code&gt;visit_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where trucks wait:&lt;/strong&gt; the gap between consecutive events in the same visit shows which stage is slow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yard hot spots:&lt;/strong&gt; count &lt;code&gt;YARD_PICK&lt;/code&gt; events per block per hour.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why automatic capture matters
&lt;/h2&gt;

&lt;p&gt;The model only works if events are recorded at the moment they happen. Manual entry adds delay and typing errors, so the timestamps drift and the analysis lies. That is why terminals pair this kind of data model with OCR and ANPR cameras at the gate and an unmanned weighbridge: the event is created by the hardware, not by a clerk.&lt;/p&gt;

&lt;p&gt;For the operational side (the quay, the yard, the gate and the KPIs terminal managers track), see this guide to &lt;a href="https://www.surajinformatics.com/2026/10/03/container-terminal-operations-how-a-modern-terminal-works-and-where-automation-cuts-delays/" rel="noopener noreferrer"&gt;container terminal operations&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>logistics</category>
      <category>iot</category>
      <category>automation</category>
      <category>database</category>
    </item>
    <item>
      <title>Computing Truck Turnaround Time from Gate Events: A Simple Data Model</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Wed, 30 Sep 2026 12:49:11 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/computing-truck-turnaround-time-from-gate-events-a-simple-data-model-2bc3</link>
      <guid>https://dev.to/suraj_informatics/computing-truck-turnaround-time-from-gate-events-a-simple-data-model-2bc3</guid>
      <description>&lt;p&gt;Plants that automate their gates with RFID or ANPR end up with a stream of events: a vehicle was seen at the gate, stood on the weighbridge, docked at bay 4, left. Turning that stream into a useful &lt;strong&gt;truck turnaround time (TAT)&lt;/strong&gt; report is a small but surprisingly fiddly data problem. Here is a simple model that works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The events
&lt;/h2&gt;

&lt;p&gt;Each reader, camera or weighbridge terminal emits an event with the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GateEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;visit_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;      &lt;span class="c1"&gt;# one truck visit (gate pass / trip number)
&lt;/span&gt;    &lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;       &lt;span class="c1"&gt;# plate or RFID tag
&lt;/span&gt;    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;         &lt;span class="c1"&gt;# REPORTED, GATE_IN, WEIGH_1, BAY_CALL, DOCK_IN, DOCK_OUT, WEIGH_2, GATE_OUT
&lt;/span&gt;    &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key design choice is &lt;code&gt;visit_id&lt;/code&gt;. Using the vehicle number alone breaks as soon as the same truck makes two trips in a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage durations
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ORDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPORTED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATE_IN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WEIGH_1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BAY_CALL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DOCK_IN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DOCK_OUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WEIGH_2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATE_OUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stage_durations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ORDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ORDER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;total_seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPORTED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATE_OUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TAT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATE_OUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPORTED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;total_seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that TAT starts at &lt;code&gt;REPORTED&lt;/code&gt;, not &lt;code&gt;GATE_IN&lt;/code&gt;. Time spent queuing outside the gate is real turnaround time, even if the gate register never sees it. An ANPR camera a little way up the approach road is the easiest way to capture it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that go wrong in real data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missing events.&lt;/strong&gt; A tag is not read at one stage. Report the visit as incomplete rather than guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate reads.&lt;/strong&gt; Readers fire several times as a truck passes. Keep the first read per stage per visit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clock drift.&lt;/strong&gt; Sync every device to one NTP source, or stage durations turn negative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value-adding vs waiting.&lt;/strong&gt; Only &lt;code&gt;DOCK_IN-&amp;gt;DOCK_OUT&lt;/code&gt; is loading. Everything else is waiting, and that is where the savings are.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;Once each stage has a duration, you can group by shift, product, transporter or gate and see exactly where trucks lose time. This is the approach behind the stage-wise TAT dashboards in GATIVRA, the plant logistics platform from Suraj Informatics.&lt;/p&gt;

&lt;p&gt;For the business side (what TAT means, the formula and seven ways to reduce it), see the full guide: &lt;a href="https://www.surajinformatics.com/2026/09/29/tat-in-logistics/" rel="noopener noreferrer"&gt;TAT in Logistics: What Truck Turnaround Time Means and How to Cut It&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>logistics</category>
      <category>python</category>
      <category>iot</category>
      <category>datamodeling</category>
    </item>
    <item>
      <title>How Weighbridge Software Moves Data from the Scale to Your ERP</title>
      <dc:creator>Suraj Informatics</dc:creator>
      <pubDate>Mon, 28 Sep 2026 17:03:17 +0000</pubDate>
      <link>https://dev.to/suraj_informatics/how-weighbridge-software-moves-data-from-the-scale-to-your-erp-12o3</link>
      <guid>https://dev.to/suraj_informatics/how-weighbridge-software-moves-data-from-the-scale-to-your-erp-12o3</guid>
      <description>&lt;p&gt;In plants, ports and logistics parks, the weighbridge is one of the few places where physical goods turn into data. Every truck is weighed at least twice (in and out), and those numbers end up on invoices, purchase orders and stock reports. If the data flow is manual, errors creep in fast.&lt;/p&gt;

&lt;p&gt;Here is a simple way to think about how modern weighbridge software moves data from the platform to the ERP.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Identify the vehicle
&lt;/h2&gt;

&lt;p&gt;Before any weight is recorded, the system needs to know &lt;strong&gt;which truck&lt;/strong&gt; is on the platform.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RFID&lt;/strong&gt; tags for regular transporters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ANPR&lt;/strong&gt; cameras that read number plates for vehicles without tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The vehicle ID is matched against an expected order or gate pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Control the platform
&lt;/h2&gt;

&lt;p&gt;Traffic lights and boom barriers let only one vehicle onto the platform at a time and hold it until it is positioned correctly. The software, not an operator, decides when the vehicle may enter and leave.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Capture a stable weight
&lt;/h2&gt;

&lt;p&gt;The software reads the &lt;strong&gt;stable&lt;/strong&gt; weight from the weight indicator and stores it with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vehicle ID&lt;/li&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;li&gt;camera image of the truck on the platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination is what makes the record tamper-proof and easy to audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Generate the ticket
&lt;/h2&gt;

&lt;p&gt;After the second weighment, gross, tare and net weights are calculated and the weighment ticket is generated automatically. No typing, no re-keying.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Sync to ERP in real time
&lt;/h2&gt;

&lt;p&gt;The record goes to a central system and, through APIs, to the ERP or terminal management system. Purchase orders, sales orders and invoices stay in sync with actual weights, instead of waiting for end-of-day uploads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Most weighbridge disputes are not about the scale. They are about &lt;strong&gt;which vehicle was weighed, and when&lt;/strong&gt;. Linking every weighment to an automatic vehicle ID and a camera image answers that before anyone has to ask.&lt;/p&gt;




&lt;p&gt;Full guide (manual vs unmanned, features to look for, FAQ): &lt;a href="https://www.surajinformatics.com/2026/09/28/what-is-weighbridge-software/" rel="noopener noreferrer"&gt;What is weighbridge software?&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suraj Informatics: &lt;a href="https://www.surajinformatics.com" rel="noopener noreferrer"&gt;https://www.surajinformatics.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Suraj Informatics UAE: &lt;a href="https://www.surajinformatics.ae" rel="noopener noreferrer"&gt;https://www.surajinformatics.ae&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GATIVRA platform: &lt;a href="https://www.gativra.com" rel="noopener noreferrer"&gt;https://www.gativra.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>iot</category>
      <category>automation</category>
      <category>logistics</category>
      <category>erp</category>
    </item>
  </channel>
</rss>
