diff --git a/lora-codec-browan/pom.xml b/lora-codec-browan/pom.xml
new file mode 100644
index 0000000000..17c96b2b6a
--- /dev/null
+++ b/lora-codec-browan/pom.xml
@@ -0,0 +1,114 @@
+
+
+
+ 4.0.0
+
+ c8y.example
+ c8y-examples
+ ${revision}${changelist}
+
+ lora-codec-browan
+ lora-codec-browan
+ http://maven.apache.org
+
+ 2.3.3.RELEASE
+ lora-codec-browan
+ lora.Application
+
+
+
+
+ com.nsn.cumulocity.clients-java
+ microservice-dependencies
+ ${revision}${changelist}
+ pom
+ import
+
+
+
+
+
+ com.nsn.cumulocity.clients-java
+ lpwan-custom-codec
+ ${c8y.version}
+
+
+ com.nsn.cumulocity.model
+ device-capability-model
+ ${c8y.version}
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot-dependencies.version}
+
+ ${main.class}
+
+
+
+
+ repackage
+
+
+
+
+
+ com.nsn.cumulocity.clients-java
+ microservice-package-maven-plugin
+ ${c8y.version}
+
+
+ package
+ package
+
+ package
+
+
+ ${microservice.name}
+ ${microservice.name}
+ UTF-8
+
+ 92m
+ 172m
+
+
+
+
+
+
+
+
+
+
+ cumulocity
+ default
+ http://download.cumulocity.com/maven/repository
+
+
+
+
+ public
+ http://download.cumulocity.com/maven/repository
+
+
+
diff --git a/lora-codec-browan/src/main/configuration/cumulocity.json b/lora-codec-browan/src/main/configuration/cumulocity.json
new file mode 100644
index 0000000000..294b88af07
--- /dev/null
+++ b/lora-codec-browan/src/main/configuration/cumulocity.json
@@ -0,0 +1,13 @@
+{
+ "apiVersion":"1",
+ "version":"@project.version@",
+ "contextPath": "lora-codec-browan",
+ "provider": {
+ "name":"Software AG"
+ },
+ "isolation":"MULTI_TENANT",
+ "requiredRoles": [
+ "ROLE_INVENTORY_ADMIN",
+ "ROLE_INVENTORY_READ"
+ ]
+}
\ No newline at end of file
diff --git a/lora-codec-browan/src/main/java/lora/Application.java b/lora-codec-browan/src/main/java/lora/Application.java
new file mode 100644
index 0000000000..c8e5079ff1
--- /dev/null
+++ b/lora-codec-browan/src/main/java/lora/Application.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012-2020 Cumulocity GmbH
+ * Copyright (c) 2022 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA,
+ * and/or its subsidiaries and/or its affiliates and/or their licensors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package lora;
+
+import com.cumulocity.microservice.lpwan.codec.annotation.CodecMicroserviceApplication;
+import org.springframework.boot.SpringApplication;
+
+@CodecMicroserviceApplication
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
\ No newline at end of file
diff --git a/lora-codec-browan/src/main/java/lora/codec/browan/BrowanCodec.java b/lora-codec-browan/src/main/java/lora/codec/browan/BrowanCodec.java
new file mode 100644
index 0000000000..a5af402bdd
--- /dev/null
+++ b/lora-codec-browan/src/main/java/lora/codec/browan/BrowanCodec.java
@@ -0,0 +1,25 @@
+package lora.codec.browan;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+import org.springframework.stereotype.Component;
+
+import com.cumulocity.microservice.lpwan.codec.Codec;
+import com.cumulocity.microservice.lpwan.codec.model.DeviceInfo;
+
+@Component
+public class BrowanCodec implements Codec {
+
+ @Override
+ public @NotNull @NotEmpty Set supportsDevices() {
+
+ DeviceInfo airQualitySensor = new DeviceInfo("Browan", "TBHV110");
+ return Collections.singleton(airQualitySensor);
+ }
+
+
+}
diff --git a/lora-codec-browan/src/main/java/lora/codec/browan/decoder/BrowanDecoder.java b/lora-codec-browan/src/main/java/lora/codec/browan/decoder/BrowanDecoder.java
new file mode 100644
index 0000000000..4dbf26c929
--- /dev/null
+++ b/lora-codec-browan/src/main/java/lora/codec/browan/decoder/BrowanDecoder.java
@@ -0,0 +1,81 @@
+package lora.codec.browan.decoder;
+
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Map;
+
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Component;
+
+import com.cumulocity.microservice.customdecoders.api.exception.DecoderServiceException;
+import com.cumulocity.microservice.customdecoders.api.model.DecoderResult;
+import com.cumulocity.microservice.customdecoders.api.model.MeasurementDto;
+import com.cumulocity.microservice.customdecoders.api.model.MeasurementValueDto;
+import com.cumulocity.microservice.customdecoders.api.service.DecoderService;
+import com.cumulocity.microservice.lpwan.codec.decoder.model.LpwanDecoderInputData;
+import com.cumulocity.model.event.CumulocitySeverities;
+import com.cumulocity.model.idtype.GId;
+import com.cumulocity.rest.representation.alarm.AlarmRepresentation;
+import com.cumulocity.rest.representation.inventory.ManagedObjects;
+import com.google.common.io.BaseEncoding;
+
+@Component
+public class BrowanDecoder implements DecoderService {
+
+ @Override
+ public DecoderResult decode(String inputData, GId deviceId, Map args) throws DecoderServiceException {
+ LpwanDecoderInputData decoderInput = new LpwanDecoderInputData(inputData, deviceId, args);
+ ByteBuffer buffer = ByteBuffer.wrap(BaseEncoding.base16().decode(inputData.toUpperCase()));
+ DecoderResult result = new DecoderResult();
+
+ if(decoderInput.getFport() == 103) {
+ buffer.get();
+ buffer.get();
+ int pcbTemperature = Byte.toUnsignedInt(buffer.get()) - 32;
+ result.addMeasurement(measurement(decoderInput, "pcb_Temperature", "T", pcbTemperature, "C"));
+ int humidity = Byte.toUnsignedInt(buffer.get());
+ result.addMeasurement(measurement(decoderInput, "c8y_Humidity", "H", humidity, "%"));
+ int co2 = Short.toUnsignedInt(Short.reverseBytes(buffer.getShort()));
+ result.addMeasurement(measurement(decoderInput, "CO2", "C", co2, "ppm"));
+ int voc = Short.toUnsignedInt(Short.reverseBytes(buffer.getShort()));
+ result.addMeasurement(measurement(decoderInput, "VOC", "V", voc, "ppm"));
+ int iaq = Short.toUnsignedInt(Short.reverseBytes(buffer.getShort()));
+ result.addMeasurement(measurement(decoderInput, "IAQ", "Q", iaq, "Q"));
+ int envTemperature = Byte.toUnsignedInt(buffer.get()) - 32;
+ result.addMeasurement(measurement(decoderInput, "c8y_Temperature", "T", envTemperature, "C"));
+
+ if(iaq > 100) {
+ result.addAlarm(alarm(deviceId, "AirQualityWarning", CumulocitySeverities.WARNING,
+ String.format("Air quality indicator > 100. Actual value: %d. Please open window", iaq)), true);
+ }
+ } else {
+ result.addAlarm(alarm(deviceId, "DecoderError", CumulocitySeverities.CRITICAL, String.format("Unknown port: %s", decoderInput.getFport())), true);
+ }
+
+ return result;
+ }
+
+ private AlarmRepresentation alarm(GId deviceId, String alarmType, CumulocitySeverities severity, String alarmText) {
+ AlarmRepresentation alarm = new AlarmRepresentation();
+ alarm.setSource(ManagedObjects.asManagedObject(deviceId));
+ alarm.setType(alarmType);
+ alarm.setSeverity(severity.name());
+ alarm.setText(alarmText);
+ alarm.setDateTime(DateTime.now());
+ return alarm;
+ }
+
+ private MeasurementDto measurement(LpwanDecoderInputData decoderInput, String fragmentName, String seriesName, long v, String unit) {
+ MeasurementDto m = new MeasurementDto();
+ m.setType(fragmentName);
+ m.setSeries(fragmentName);
+ MeasurementValueDto value = new MeasurementValueDto();
+ value.setSeriesName(seriesName);
+ value.setValue(BigDecimal.valueOf(v));
+ value.setUnit(unit);
+ m.setValues(Collections.singletonList(value));
+ m.setTime(new DateTime(decoderInput.getUpdateTime() != null?decoderInput.getUpdateTime() : System.currentTimeMillis()));
+ return m;
+ }
+}
diff --git a/lora-codec-browan/src/main/java/lora/codec/browan/encoder/BrowanEncoder.java b/lora-codec-browan/src/main/java/lora/codec/browan/encoder/BrowanEncoder.java
new file mode 100644
index 0000000000..0628b3c73f
--- /dev/null
+++ b/lora-codec-browan/src/main/java/lora/codec/browan/encoder/BrowanEncoder.java
@@ -0,0 +1,22 @@
+package lora.codec.browan.encoder;
+
+import org.springframework.stereotype.Component;
+
+import com.cumulocity.microservice.customencoders.api.exception.EncoderServiceException;
+import com.cumulocity.microservice.customencoders.api.model.EncoderInputData;
+import com.cumulocity.microservice.customencoders.api.model.EncoderResult;
+import com.cumulocity.microservice.customencoders.api.service.EncoderService;
+import com.cumulocity.microservice.lpwan.codec.encoder.model.LpwanEncoderResult;
+
+@Component
+public class BrowanEncoder implements EncoderService {
+
+ @Override
+ public EncoderResult encode(EncoderInputData arg0) throws EncoderServiceException {
+ LpwanEncoderResult encoderResult = new LpwanEncoderResult();
+ encoderResult.setSuccess(false);
+ encoderResult.setMessage("Encoding Payload Failed");
+ return encoderResult;
+ }
+
+}
diff --git a/lora-codec-browan/src/main/resources/application.properties b/lora-codec-browan/src/main/resources/application.properties
new file mode 100644
index 0000000000..b1497bff21
--- /dev/null
+++ b/lora-codec-browan/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2012-2020 Cumulocity GmbH
+# Copyright (c) 2022 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA,
+# and/or its subsidiaries and/or its affiliates and/or their licensors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+application.name=lora-codec-browan
\ No newline at end of file
diff --git a/lora-codec-browan/src/main/resources/logback-spring.xml b/lora-codec-browan/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000000..e0ad568c38
--- /dev/null
+++ b/lora-codec-browan/src/main/resources/logback-spring.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+ ${LOG_FILE}
+
+
+ ${LOG_FILE}.%d{yyyy-MM-dd}.log
+
+
+ 30
+ 1GB
+
+
+ ${FILE_LOG_PATTERN}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file