ranges

ranges #

ranges is an optional request parameter, which should hold the ranges in which the display readings are expected to fall in. Providing this parameter might result in more accurate readings by Blicker. In addition, it can be used to verify that the readings by Blicker are in line with the expectations.

If historical data about the meter readings for a certain end-user are known, and an estimation can be made about the expected meter readings, then this could be passed to Blicker. Blicker can use this to verify whether the meter readings are in line with the expectations, and also correct the meter reading if it does not match.

Blicker will always first try to read the displays without using the provided ranges. These read values are stored as the valueBeforeCorrection property in the respective display objects in the response. After this, it will check whether the read values are within the expected range. If so, the readings will not be corrected. The value will then be the same as the valueBeforeCorrection.
However, in some cases Blicker may not have read the display correctly. For example, it might have mistaken a “1” (one) for a “7” (seven), or it might have not detected a certain digit. In these cases, Blicker might make small corrections to the read value in order to make the value fall in the expected range. This corrected value will be stored as the value, while the original value will still be stored as the valueBeforeCorrection.

The ranges should be provided as an encoded JSON object that contains the expected ranges per display. The JSON object should contain a key for each display number to check (starting with 0) that maps to another object that contains a min and/or max field containing a decimal number. As an example:

{"0": {"min": 10000, "max": 12000}, "1": {"min": 999}}

Examples of the ranges being used in actual requests can be found below.

Version info
Before the the 2020-10-01 release, this request parameter had no effect.

Best practices #

The expected ranges are often based on historical data. The minimum value can, for example, be set to the value of the previous meter reading. The maximum value can be set by making reasonable estimations based on historical data points of meter readings.

It is not required to set both the minimum and maximum value. You could also provide only either of them. It is however recommended to set both in most cases. When only a minimum or only a maximum value is provided, the chance is small that the detected value will be outside of the expected range, and Blicker will often be unable to apply any corrections.

It is often better to overestimate the maximum value rather than to underestimate it. When Blicker reads out a meter correctly, but the maximum expected value is too small, Blicker will still try to correct the reading to make it fall in the expected range, which could result in an incorrect reading.

Example requests #

This test image has two displays with readings “51289” and “57266” respectively, which Blicker reads out correctly. We will show examples where the readngs are correctly validated, and examples where the readings will and will not be corrected.

Correct validation #

Lets first see what happens when we provide correct ranges.

curl -X 'POST' \
  'https://api.blicker.ai/blicker/2020-10-01' \
  -H 'subscription-key: <your subscription key>' \
  -F 'image=@test_image.jpg' \
  -F 'ranges={"0":{"min":51200,"max":51300},"1":{"min":57200,"max":57300}}'
import json
from pathlib import Path
from pprint import pprint

import requests

ranges = json.dumps({"0": {"min": 51200, "max": 51300}, "1": {"min": 57200, "max": 57300}})

response = requests.post(
    "https://api.blicker.ai/blicker/2020-10-01",
    headers={"subscription-key": "<your subscription key>"},
    files={"image": ("test_image.jpg", Path("test_image.jpg").read_bytes())},
    data={"ranges": ranges},
)

pprint(response.json())
Info
Note that the exact syntax of double quotations marks is important. Otherwise the string could not be interpreted as a valid JSON object.

In the response, we see that the respective display objects will contain the ranges against which they were validated, and we see that Blicker has not made any corrections, as the values fell within the specified ranges.

{
   "messages":[],
   "objects":{
      "meter":[
         {
            "messages":[],
            "objects":{
               "display":[
                  {
                     "index":0,
                     "messages":[],
                     "objectId":"o-XXWCzmWh",
                     "value":"51289",
                     "range":{
                        "min":51200.0,
                        "max":51300.0
                     },
                     "valueBeforeCorrection":"51289"
                  },
                  {
                     "index":1,
                     "messages":[],
                     "objectId":"o-KbNqPXVV",
                     "value":"57266",
                     "range":{
                        "min":57200.0,
                        "max":57300.0
                     },
                     "valueBeforeCorrection":"57266"
                  }
               ],
            }
         }
      ]
   }
}

Display reading correction #

Now let’s look at an example where Blicker corrects the read value. Let’s imagine that in the first display, the “1” (one) should actually have been a “7” (seven), while in the second display the value should actually have been “572.66” (the decimal separator should have been in a different place).

curl -X 'POST' \
  'https://api.blicker.ai/blicker/2020-10-01' \
  -H 'subscription-key: <your subscription key>' \
  -F 'image=@test_image.jpg' \
  -F 'ranges={"0":{"min":57200,"max":57300},"1":{"min":572,"max":573}}'
import json
from pathlib import Path
from pprint import pprint

import requests

ranges = json.dumps({"0": {"min": 57200, "max": 57300}, "1": {"min": 572, "max": 573}})

response = requests.post(
    "https://api.blicker.ai/blicker/2020-10-01",
    headers={"subscription-key": "<your subscription key>"},
    files={"image": ("test_image.jpg", Path("test_image.jpg").read_bytes())},
    data={"ranges": ranges},
)

pprint(response.json())

In the response, the display readings will now be corrected, while the original value can still be accessed as the valueBeforeCorrection.

{
   "messages":[
      {
         "code":"uneven_displays",
         "message":"Displays with different numbers of digits have been found.",
         "messageId":"m-VtieKiJJ",
         "objectId":"o-jDjZd7hJ"
      }
   ],
   "objects":{
      "meter":[
         {
            "messages":["m-VtieKiJJ"],
            "objects":{
               "display":[
                  {
                     "index":0,
                     "messages":[],
                     "objectId":"o-pXAmdSeM",
                     "value":"57289",
                     "range":{
                        "min":57200.0,
                        "max":57300.0
                     },
                     "valueBeforeCorrection":"51289"
                  },
                  {
                     "index":1,
                     "messages":[],
                     "objectId":"o-JvV9booj",
                     "value":"572.66",
                     "range":{
                        "min":572.0,
                        "max":573.0
                     },
                     "valueBeforeCorrection":"57266"
                  }
               ]
            }
         }
      ]
   }
}

No display reading correction #

Lastly we will show an example where Blicker will not make any corrections, even when the meter readings are outside of the expected ranges. Blicker will only avoid applying too many corrections to prevent situations where completely wrong values are returned.

The first display reading in the following example is not corrected to be in the range 100000-200000 because it would have to change more than one digit. The second display is also not corrected, because the need to prepend a “1” (one) is too unlikely.

curl -X 'POST' \
  'https://api.blicker.ai/blicker/2020-10-01' \
  -H 'subscription-key: <your subscription key>' \
  -F 'image=@test_image.jpg' \
  -F 'ranges={"0":{"min":100000,"max":200000},"1":{"min":157200,"max":157300}}'
import json
from pathlib import Path
from pprint import pprint

import requests

ranges = json.dumps({"0": {"min": 100000, "max": 200000}, "1": {"min": 157200, "max": 157300}})

response = requests.post(
    "https://api.blicker.ai/blicker/2020-10-01",
    headers={"subscription-key": "<your subscription key>"},
    files={"image": ("test_image.jpg", Path("test_image.jpg").read_bytes())},
    data={"ranges": ranges},
)

pprint(response.json())

In the response we see that none of the displays have been corrected, which is also indicated by the messages.

{
   "messages":[
      {
         "code":"no_match_expected_display_range",
         "message":"The meter reading is outside the expected range.",
         "messageId":"m-3WitTvoM",
         "objectId":"o-EE3tDXe8"
      },
      {
         "code":"no_match_expected_display_range",
         "message":"The meter reading is outside the expected range.",
         "messageId":"m-d5AJkvbu",
         "objectId":"o-nzL8nRfw"
      }
   ],
   "objects":{
      "meter":[
         {
            "messages":[],
            "objectId":"o-q5JWNikU",
            "objects":{
               "display":[
                  {
                     "index":0,
                     "messages":["m-3WitTvoM"],
                     "objectId":"o-EE3tDXe8",
                     "value":"51289",
                     "range":{
                        "min":100000.0,
                        "max":200000.0
                     },
                     "valueBeforeCorrection":"51289"
                  },
                  {
                     "index":1,
                     "messages":["m-d5AJkvbu"],
                     "objectId":"o-nzL8nRfw",
                     "value":"57266",
                     "range":{
                        "min":157200.0,
                        "max":157300.0
                     },
                     "valueBeforeCorrection":"57266"
                  }
               ]
            }
         }
      ]
   }
}