Meter Plugin


Examples Source Code

The source code of all example use cases of the Meter plugin can be found in the Android SDK Bundle

Module Description

Simultaneous Barcode Scanning

Starting from SDK 3.8 Anyline supports simultaneous barcode scanning for any module. Additional Information on how to implement this on Android an be found at Simultaneous Barcode Scanning

The Anyline Meter plugin is capable of scanning Analog Electric-, Gas- and Water Meter readings. It is also possible to scan Bar- and QR-codes, which is useful for identifying meters, as well as the Serial Number. Common 7-segment Digital Meters and Heat Meters can also be scanned.

The description of all parameters can be found at Plugins > Meter

How to implement the Meter Plugin

This is a step by step guide on how to implement the Meter Plugins in Android.

Get the Meter Plugin in Java

Changes in 4

Starting with Anyline 4, the ScanView is a generic type which should not be cast to each scan view types

First add the Scan View to your xml-layout.

Add the ScanView to the layout
<!--
  ~ Anyline
  ~ activity_scan_energy.xmll
  ~
  ~ Copyright (c) 2015 9yards GmbH
  ~
  -->

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_layout"
    android:animateLayoutChanges="true">


    <io.anyline.view.ScanView
        android:id="@+id/scan_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>

In the next step, go to your Java Activity code and get the view from the layout in onCreate() or onActivityCreated()

Get the Scan View
        // get the view from the layout (check out the xml for the configuration of the view)
        energyScanView = (ScanView) findViewById(R.id.scan_view);

Set your Scan Mode

All Meter-related use cases can be started from the Meter Plugin by setting the Scan Mode to the respective use case.

setScanMode
        // ANALOG_METER will work for all types of analog meters (gas, electric, water) and
        // automatically detects digits before and after the point
        ((MeterScanViewPlugin)energyScanView.getScanViewPlugin()).setScanMode(MeterScanMode.AUTO_ANALOG_DIGITAL_METER);
Mode Parameter in Module Description
MeterScanMode.AUTO_ANALOG_DIGITAL_METER Auto Analog/Digital Meter Description
MeterScanMode.ANALOG_METER Analog Meter Description
MeterScanMode.DIGITAL_METER Digital Meter Description
MeterScanMode.BARCODE Barcode Description
MeterScanMode.SERIAL_NUMBER Serial Number Description
MeterScanMode.DIAL_METER Dial Meter Description
MeterScanMode.DOT_MATRIX_METER Dot Matrix Meter Description

Initialize and Configure Anyline

ScanViewPlugin

Initialize ScanViewPlugin configuration

Limitations for the Meter Module

The Capture Resolution is fixed to 720p as this provides the best results
The Size and Ratio are fixed and optimised for the best results
The Cutout Alignment should be set to TOP with a little offset, as this reduces reflections

The ScanViewPlugin configuration holds the UI properties for cutout and visual feedback.

Initialize the ScanViewPlugin configuration
        //init the scanViewPlugin configuration which hold the scan view ui configuration (cutoutConfig and ScanFeedbackConfig)		
	ScanViewPluginConfig energyScanviewPluginConfig = new ScanViewPluginConfig(getApplicationContext(), "energy_view_config.json");

Initialize ScanViewPlugin

Together with your Anyline License Key Generation, you can now initialise MeterScanViewPugin. The MeterScanViewPugin will internally initialize the BarcodeScanPlugin. In java, this should be called in onCreate() or onActivityCreated().

Initialize the ScanViewPlugin
	//init the scan view
	MeterScanViewPlugin scanViewPlugin = new MeterScanViewPlugin(getApplicationContext(), getString(R.string.anyline_license_key), energyScanviewPluginConfig, "METER");

ScanView

Set the Base Configuration

The base configurations are holding the camera and the flash properties. You can set it the following way, also in onCreate() or onActivityCreated()

Set the Base Configuration(Camera and Flash configuration) and the View Configuration (Cutout and ScanView configuration)
	//init the base scanViewconfig which hold camera and flash configuration
	BaseScanViewConfig energyBaseScanViewConfig = new BaseScanViewConfig(getApplicationContext(), "energy_view_config.json");
	//set the base scanViewConfig to the ScanView
	energyScanView.setScanViewConfig(energyBaseScanViewConfig);

Set the ScanViewPlugin to the ScanView

A ScanView is holding a ScanViewPlugin, therefore a ScanViewPlugin has to be set to the ScanView.

Set the ScanViewPlugin to the ScanView
	//set the scanViewPlugin to the ScanView
	energyScanView.setScanViewPlugin(scanViewPlugin);

The Meter Result Listener

Changes in 4

The result listener changed in version 4.

With Anyline 4, all listeners are called ScanResultListener. In case of the Meter Plugin, the listener is of type MeterScanResult. This section describes the ScanResultListener callback in detail.

In the Meter Plugin of Anyline SDK, you will be provided the final results via a ResultListener.

onResult

This is the main callback method for the Meter Plugin. It is called once a valid result has been found.

The result is an instance of MeterScanResult, which holds the detected text, the scanMode that was used, the outline of the text on the frame, the confidence of the result, the image that was processed, as well as a cutout image and the full image.

See MeterScanResult in the Javadocs

  • result

Changed in version 3.10.

Start Scanning

After everything is initialised, you can start the scanning process, by calling start() on the meterScanView. It is advised to place this call in the onResume() lifecycle method of Android.

startScanning
    @Override
    protected void onResume() {
        super.onResume();
        //start the actual scanning
        energyScanView.start();
    }

Stop Scanning

To stop the scanning process, call stop() on the meterScanView.

To make sure the SDK is properly stopped upon leaving the Activity, make sure to place cancelScanning() and releaseCamera()/releaseCameraInBackground() in the onPause() lifecycle method of Android.

stopScanning
    @Override
    protected void onPause() {
        super.onPause();
        //stop the scanning
        energyScanView.stop();
        //release the camera (must be called in onPause, because there are situations where
        // it cannot be auto-detected that the camera should be released)
        energyScanView.releaseCameraInBackground();
    }

Full Example Activity

Meter Module Example
package io.anyline.examples.meter;

import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.CompoundButton;
import android.widget.Switch;

import at.nineyards.anyline.camera.CameraController;
import at.nineyards.anyline.camera.CameraOpenListener;
import at.nineyards.anyline.models.AnylineImage;
import at.nineyards.anyline.modules.barcode.NativeBarcodeResultListener;
import at.nineyards.anyline.modules.energy.EnergyResult;
import at.nineyards.anyline.modules.energy.EnergyResultListener;
import at.nineyards.anyline.modules.energy.EnergyScanView;
import io.anyline.examples.R;
import io.anyline.examples.ResultDialogBuilder;
import io.anyline.examples.SettingsFragment;

/**
 * Example activity for the Anyline-Energy-Module
 */
public class ScanAutoAnalogMeterActivity extends AppCompatActivity implements CameraOpenListener {

    private static final String TAG = ScanAnalogMeterActivity.class.getSimpleName();
    protected ScanView energyScanView;
    private String lastDetectedBarcodeValue = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan_energy);

        // get the view from the layout (check out the xml for the configuration of the view)
        energyScanView = (ScanView) findViewById(R.id.scan_view);

        Switch barcodeDetectionSwitch = (Switch) findViewById(R.id.barcode_scanner_switch);

        // set a listener on the switch to enable and disable barcode detection
        barcodeDetectionSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
                lastDetectedBarcodeValue = "";
                if (isChecked) {
                    Log.d(TAG, "barcode detection enabled");

                    // enables the barcode detection for the full image (the preview view, rather than the cutout only)
                    energyScanView.enableBarcodeDetection(new NativeBarcodeResultListener() {
                        @Override
                        public void onBarcodesReceived(SparseArray<com.google.android.gms.vision.barcode.Barcode> sparseArray) {

                            // For this demonstration purpose, we only use the latest barcode that has been found.
                            // However, note that you receive a list of barcodes, e.g. it detects multiple barcodes at once.
                            // Also the listener is called every time barcodes are found on a frame,
                            // so it is independent from the energy result
                            if (sparseArray.size() > 0) {
                                lastDetectedBarcodeValue = sparseArray.valueAt(0).displayValue;
                            }
                        }
                    });
                } else {
                    Log.d(TAG, "barcode detection disabled");
                    energyScanView.disableBarcodeDetection();
                }
            }
        });

        // add a camera open listener that will be called when the camera is opened or an error occurred
        //  this is optional (if not set a RuntimeException will be thrown if an error occurs)
        energyScanView.setCameraOpenListener(this);

        // set reporting according to prefs or true on default
        energyScanView.setReportingEnabled(PreferenceManager.getDefaultSharedPreferences(this).getBoolean(SettingsFragment
                .KEY_PREF_REPORTING_ON, true));
        //init the scanViewPlugin configuration which hold the scan view ui configuration (cutoutConfig and ScanFeedbackConfig)		
	ScanViewPluginConfig energyScanviewPluginConfig = new ScanViewPluginConfig(getApplicationContext(), "energy_view_config.json");
	//init the scan view
	MeterScanViewPlugin scanViewPlugin = new MeterScanViewPlugin(getApplicationContext(), getString(R.string.anyline_license_key), energyScanviewPluginConfig, "METER");
	//init the base scanViewconfig which hold camera and flash configuration
	BaseScanViewConfig energyBaseScanViewConfig = new BaseScanViewConfig(getApplicationContext(), "energy_view_config.json");
	//set the base scanViewConfig to the ScanView
	energyScanView.setScanViewConfig(energyBaseScanViewConfig);
	//set the scanViewPlugin to the ScanView
	energyScanView.setScanViewPlugin(scanViewPlugin);
	//add result listener
	scanViewPlugin.addScanResultListener(new ScanResultListener<MeterScanResult>() {
		@Override
		public void onResult(MeterScanResult energyResult) {
			new ResultDialogBuilder(ScanAnalogMeterActivity.this)
                        .setResultImage(energyResult.getCutoutImage())
                        .setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22)
                        .setTextGravity(Gravity.CENTER)
                        .setText(energyResult.getResult())
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // reset the last detected barcode value, as it has already been displayed
                                lastDetectedBarcodeValue = "";
                                if (!energyScanView.isRunning()) {
                                    energyScanView.startScanning();
                                }
                            }
                        })
                        .setTitle(getString(R.string.title_analog_meter))
                        .setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface dialogInterface) {
                                // reset the last detected barcode value, as it has already been displayed
                                lastDetectedBarcodeValue = "";
                                if (!energyScanView.isRunning()) {
                                    energyScanView.startScanning();
                                }
                            }
                        })
                        .show();
		}
	});

        // ANALOG_METER will work for all types of analog meters (gas, electric, water) and
        // automatically detects digits before and after the point
        ((MeterScanViewPlugin)energyScanView.getScanViewPlugin()).setScanMode(MeterScanMode.AUTO_ANALOG_DIGITAL_METER);
    }


    @Override
    protected void onResume() {
        super.onResume();
        //start the actual scanning
        energyScanView.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //stop the scanning
        energyScanView.stop();
        //release the camera (must be called in onPause, because there are situations where
        // it cannot be auto-detected that the camera should be released)
        energyScanView.releaseCameraInBackground();
    }

    @Override
    public void onCameraOpened(final CameraController cameraController, int width, int height) {
        //the camera is opened async and this is called when the opening is finished
        Log.d(TAG, "Camera opened successfully. Frame resolution " + width + " x " + height);
    }

    @Override
    public void onCameraError(Exception e) {
        //This is called if the camera could not be opened.
        // (e.g. If there is no camera or the permission is denied)
        // This is useful to present an alternative way to enter the required data if no camera exists.
        throw new RuntimeException(e);
    }

}