DIGIPIN の生成と復号化を行う

中級

これはEngineering分野の自動化ワークフローで、12個のノードを含みます。主にCode, Switch, Webhook, RespondToWebhookなどのノードを使用。 INDIA 向けの高精細位置マッピングを目のとした、オフライン DIGIPIN マイクロサービス API を作成

前提条件
  • HTTP Webhookエンドポイント(n8nが自動生成)
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "id": "OcAQrF91wzWH3rOw",
  "meta": {
    "instanceId": "97cf5417030d41ab2642f97a3d99e6a9359587b310a5d986917e2d084e12ce17"
  },
  "name": "Generate and Decode DIGIPIN",
  "tags": [],
  "nodes": [
    {
      "id": "882aa556-8ea2-4582-8230-7b0e13ad2fd1",
      "name": "Webhookへの応答 - 成功",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        340,
        -140
      ],
      "parameters": {
        "options": {
          "responseCode": 200
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"Success\",\n  \"lat\": \"{{ $json.query.lat }}\",\n  \"lon\": \"{{ $json.query.lon }}\",\n  \"digipin\": \"{{ $json.digipin }}\"\n} "
      },
      "typeVersion": 1.4
    },
    {
      "id": "368240b0-cecf-46e7-9509-bfcb1afe7610",
      "name": "Webhookへの応答 - エラー",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        340,
        60
      ],
      "parameters": {
        "options": {
          "responseCode": 422
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"Failed\",\n  \"lat\": \"{{ $json.query.lat }}\",\n  \"lon\": \"{{ $json.query.lon }}\",\n  \"error\": \"{{ $json.error }}\"\n} "
      },
      "typeVersion": 1.4
    },
    {
      "id": "b6c70cd6-3d5f-4215-989c-8a5e6a896564",
      "name": "スイッチ - 成功確認",
      "type": "n8n-nodes-base.switch",
      "position": [
        120,
        -40
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "digipin",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "3656e246-523a-4611-b563-8e66ae078d67",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.digipin }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9b5ef11d-7833-41c3-8611-56cf11df2dcc",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.error }}",
                    "rightValue": ""
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "3a7dc7a2-9d19-467c-b651-143187d852d9",
      "name": "DIGIPIN生成コード",
      "type": "n8n-nodes-base.code",
      "position": [
        -100,
        -40
      ],
      "parameters": {
        "jsCode": "// --- DIGIPIN Generation Logic ---\n\n// Constants for DIGIPIN generation\nconst DIGIPIN_GRID = [\n    ['F', 'C', '9', '8'],\n    ['J', '3', '2', '7'],\n    ['K', '4', '5', '6'],\n    ['L', 'M', 'P', 'T']\n];\n\nconst BOUNDS = {\n    minLat: 2.5,\n    maxLat: 38.5,\n    minLon: 63.5,\n    maxLon: 99.5\n};\n\n/**\n * Encodes latitude and longitude into a DIGIPIN.\n * @param {number} lat The latitude.\n * @param {number} lon The longitude.\n * @returns {string} The generated DIGIPIN.\n * @throws {Error} If coordinates are out of bounds.\n */\nfunction generateDigiPin(lat, lon) {\n    if (lat < BOUNDS.minLat || lat > BOUNDS.maxLat || lon < BOUNDS.minLon || lon > BOUNDS.maxLon) {\n        throw new Error(`Coordinates (Lat: ${lat}, Lon: ${lon}) are out of the valid range.`);\n    }\n\n    let minLat = BOUNDS.minLat, maxLat = BOUNDS.maxLat;\n    let minLon = BOUNDS.minLon, maxLon = BOUNDS.maxLon;\n    let digiPin = '';\n\n    for (let level = 1; level <= 10; level++) {\n        const latDiv = (maxLat - minLat) / 4;\n        const lonDiv = (maxLon - minLon) / 4;\n        let row = 3 - Math.floor((lat - minLat) / latDiv);\n        let col = Math.floor((lon - minLon) / lonDiv);\n        row = Math.max(0, Math.min(row, 3));\n        col = Math.max(0, Math.min(col, 3));\n        digiPin += DIGIPIN_GRID[row][col];\n        if (level === 3 || level === 6) {\n            digiPin += '-';\n        }\n        maxLat = minLat + latDiv * (4 - row);\n        minLat = minLat + latDiv * (3 - row);\n        minLon = minLon + lonDiv * col;\n        maxLon = minLon + lonDiv;\n    }\n    return digiPin;\n}\n\n\n// --- n8n Item Processing ---\n// Loop through each input item provided to the node.\nfor (const item of items) {\n    try {\n        // Get latitude and longitude from the input item's JSON data.\n        // Assumes the previous node provides these fields.\n        const lat = $input.first().json.query.lat;\n        const lon = $input.first().json.query.lon;\n\n        if (lat === undefined || lon === undefined) {\n            throw new Error(\"Input item is missing 'latitude' or 'longitude' field.\");\n        }\n\n        // Generate the DIGIPIN.\n        const digipinResult = generateDigiPin(lat, lon);\n\n        // Add the result to a new field called 'digipin' in the item's JSON.\n        item.json.digipin = digipinResult;\n\n    } catch (error) {\n        // If an error occurs, add an 'error' field to the item.\n        // This helps with debugging in the n8n UI.\n        item.json.error = error.message;\n    }\n}\n\n// Return all the modified items to the next node in the workflow.\nreturn items;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "33aab4da-4b77-44fa-85c4-0ed165b416d3",
      "name": "DIGIPINデコードコード",
      "type": "n8n-nodes-base.code",
      "position": [
        -100,
        420
      ],
      "parameters": {
        "jsCode": "/**\n * Decodes a DIGIPIN into latitude and longitude coordinates.\n * @param {string} digiPin The DIGIPIN to decode.\n * @returns {{latitude: string, longitude: string}} An object containing the latitude and longitude,\n * each formatted to 6 decimal places.\n * @throws {Error} If the DIGIPIN is invalid or contains invalid characters.\n */\nconst DIGIPIN_GRID = [\n    ['F', 'C', '9', '8'],\n    ['J', '3', '2', '7'],\n    ['K', '4', '5', '6'],\n    ['L', 'M', 'P', 'T']\n];\n\n\nconst BOUNDS = {\n    minLat: 2.5,\n    maxLat: 38.5,\n    minLon: 63.5,\n    maxLon: 99.5\n};\nfunction getLatLngFromDigiPin(digiPin) {\n    const pin = digiPin.replace(/-/g, ''); // Remove hyphens for processing\n    if (pin.length !== 10) throw new Error('Invalid DIGIPIN: Must be 10 characters long after removing hyphens.');\n\n    let minLat = BOUNDS.minLat;\n    let maxLat = BOUNDS.maxLat;\n    let minLon = BOUNDS.minLon;\n    let maxLon = BOUNDS.minLon; // Corrected initial value here, should be BOUNDS.minLon\n\n    // Recalculate maxLon for accurate initial bounds\n    // Based on the original DIGIPIN generation, it should cover the whole range initially.\n    maxLon = BOUNDS.maxLon;\n\n\n    for (let i = 0; i < 10; i++) {\n        const char = pin[i];\n        let found = false;\n        let ri = -1, ci = -1;\n\n        for (let r = 0; r < 4; r++) {\n            for (let c = 0; c < 4; c++) {\n                if (DIGIPIN_GRID[r][c] === char) {\n                    ri = r;\n                    ci = c;\n                    found = true;\n                    break;\n                }\n            }\n            if (found) break;\n        }\n\n        if (!found) throw new Error(`Invalid character '${char}' in DIGIPIN.`);\n\n        const latDiv = (maxLat - minLat) / 4;\n        const lonDiv = (maxLon - minLon) / 4;\n\n        const lat1 = maxLat - latDiv * (ri + 1);\n        const lat2 = maxLat - latDiv * ri;\n        const lon1 = minLon + lonDiv * ci;\n        const lon2 = minLon + lonDiv * (ci + 1);\n\n        minLat = lat1;\n        maxLat = lat2;\n        minLon = lon1;\n        maxLon = lon2;\n    }\n\n    const centerLat = (minLat + maxLat) / 2;\n    const centerLon = (minLon + maxLon) / 2;\n\n    return {\n        latitude: centerLat.toFixed(6),\n        longitude: centerLon.toFixed(6)\n    };\n}\n\n\nconst MY_DIGIPIN = $input.first().json.query.digipin; // <--- REPLACE THIS with your desired DIGIPIN\n\n// Ensure there's at least one item to process, or create a dummy one\nlet outputItems = [];\nif (items.length === 0) {\n    // If no items come into the node, create a blank one to attach results to\n    outputItems.push({ json: {} });\n} else {\n    // If items exist, clone them to add results\n    outputItems = JSON.parse(JSON.stringify(items));\n}\n\nfor (const item of outputItems) {\n    try {\n        const digipinToProcess = MY_DIGIPIN;\n\n        if (!digipinToProcess) {\n            throw new Error(\"No DIGIPIN specified for processing.\");\n        }\n\n        // Decode the DIGIPIN\n        const decodedCoords = getLatLngFromDigiPin(digipinToProcess);\n\n        // Add the result to new fields in the item's JSON\n        item.json.processedDigipin = digipinToProcess; // Optional: To see which digipin was processed\n        item.json.decodedLatitude = decodedCoords.latitude;\n        item.json.decodedLongitude = decodedCoords.longitude;\n\n    } catch (error) {\n        // If an error occurs, add an 'error' field to the item.\n        item.json.error = error.message;\n    }\n}\n\n// Return all the modified items to the next node in the workflow.\nreturn outputItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "6da5b090-caf7-4a8b-a254-a90ac9b97610",
      "name": "エンコードWebhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -320,
        -40
      ],
      "webhookId": "8f08f857-3a7e-4b46-97fb-7de6812e9204",
      "parameters": {
        "path": "generate-digipin",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "99a30d16-696a-4c2c-941d-7b66a6591d54",
      "name": "デコードWebhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -320,
        420
      ],
      "webhookId": "8f08f857-3a7e-4b46-97fb-7de6812e9204",
      "parameters": {
        "path": "decode-digipin",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "ab871baf-aae7-4060-83af-7794974dce18",
      "name": "スイッチ2 - 成功確認1",
      "type": "n8n-nodes-base.switch",
      "position": [
        120,
        420
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "coordinates",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "3656e246-523a-4611-b563-8e66ae078d67",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.decodedLatitude }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9b5ef11d-7833-41c3-8611-56cf11df2dcc",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.error }}",
                    "rightValue": ""
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "64409e6c-e4aa-41b2-abcf-a016e729ea37",
      "name": "Webhookへの応答 - 成功2",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        340,
        320
      ],
      "parameters": {
        "options": {
          "responseCode": 200
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"Success\",\n  \"digipin\": \"{{ $json.query.digipin }}\",\n  \"lat\": \"{{ $json.decodedLatitude }}\",\n  \"lon\": \"{{ $json.decodedLongitude }}\"\n} "
      },
      "typeVersion": 1.4
    },
    {
      "id": "d37184ce-7060-4d06-b039-dd8572e7d3e8",
      "name": "Webhookへの応答 - エラー2",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        340,
        520
      ],
      "parameters": {
        "options": {
          "responseCode": 422
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"Failed\",\n  \"digipin\": \"{{ $json.query.digipin }}\",\n  \"error\": \"{{ $json.error }}\"\n} "
      },
      "typeVersion": 1.4
    },
    {
      "id": "8d745b4f-f993-4865-a96f-e3f1e28a0cc2",
      "name": "付箋ノート",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        660,
        360
      ],
      "parameters": {
        "color": 4,
        "width": 920,
        "height": 320,
        "content": "## Example usage \n\nGenerate a DIGIPIN:\n```\ncurl --request GET \\\n  --url 'https://n8n.example.in/webhook/generate-digipin?lat=27.175063&lon=78.042169'\n```\n\nDecode a DIGIPIN:\n```\ncurl --request GET \\\n  --url 'https://n8n.example.in/webhook/decode-digipin?digipin=32C-849-5CJ6'\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "3cb47a09-ce41-4d2d-a413-885510ebda96",
      "name": "付箋ノート1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        660,
        -160
      ],
      "parameters": {
        "width": 920,
        "height": 440,
        "content": "## DIGIPIN Generator and Decoder\n\nThis n8n workflow lets you **generate and decode DIGIPINs** using only JavaScript - no external APIs involved.\n\nDIGIPIN is India Post’s geolocation code system that encodes latitude and longitude into a 10-character alphanumeric string, like `32C-849-5CJ6`. It helps simplify precise location sharing across India.\n\n### 🔧 What it does\n- `/generate-digipin?lat=...&lon=...` → returns the DIGIPIN for given coordinates\n- `/decode-digipin?digipin=...` → returns the coordinates for a given DIGIPIN\n\nUseful for: check-in systems, last-mile delivery, digital address verification, or simple location sharing.\n\n### ⚙️ How to use\n- Add your own webhook URLs or run locally\n- Pass query parameters to trigger either route\n- Both encode/decode logic is handled inside Function nodes\n\nNo credentials, APIs, or setup required.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "9226c009-d942-4f3c-b982-9f7dbb73d710",
  "connections": {
    "99a30d16-696a-4c2c-941d-7b66a6591d54": {
      "main": [
        [
          {
            "node": "33aab4da-4b77-44fa-85c4-0ed165b416d3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6da5b090-caf7-4a8b-a254-a90ac9b97610": {
      "main": [
        [
          {
            "node": "3a7dc7a2-9d19-467c-b651-143187d852d9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "33aab4da-4b77-44fa-85c4-0ed165b416d3": {
      "main": [
        [
          {
            "node": "ab871baf-aae7-4060-83af-7794974dce18",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3a7dc7a2-9d19-467c-b651-143187d852d9": {
      "main": [
        [
          {
            "node": "b6c70cd6-3d5f-4215-989c-8a5e6a896564",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b6c70cd6-3d5f-4215-989c-8a5e6a896564": {
      "main": [
        [
          {
            "node": "882aa556-8ea2-4582-8230-7b0e13ad2fd1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "368240b0-cecf-46e7-9509-bfcb1afe7610",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ab871baf-aae7-4060-83af-7794974dce18": {
      "main": [
        [
          {
            "node": "64409e6c-e4aa-41b2-abcf-a016e729ea37",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "d37184ce-7060-4d06-b039-dd8572e7d3e8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

中級 - エンジニアリング

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
中級
ノード数12
カテゴリー1
ノードタイプ5
難易度説明

経験者向け、6-15ノードの中程度の複雑さのワークフロー

作成者
Srinivasan KB

Srinivasan KB

@srinivasankb

Product Manager in B2B SaaS product focused on CX management. Interested in building AI powered workflows that can automate or simplify the routine and complex tasks.

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34