[VOL-3695]: Support to create some of the OLT device events over the Device Management Interface
    1. Following events and its corresponding recovered event creation is supported :
       EVENT_FAN_FAILURE
       EVENT_PSU_FAILURE
       EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL
    2. Following DMI Native Events Management Service APIs are implemented:
       ListEvents
       UpdateEventsConfiguration
    3. Updated docs/source/DMI_Server_README.md

Change-Id: Ibc48302b61fd52a2f83bd888731f611eaf6c4c37
diff --git a/internal/bbsim/dmiserver/dmi_api_server.go b/internal/bbsim/dmiserver/dmi_api_server.go
index f64f801..272f3c9 100755
--- a/internal/bbsim/dmiserver/dmi_api_server.go
+++ b/internal/bbsim/dmiserver/dmi_api_server.go
@@ -20,6 +20,7 @@
 	"context"
 	"net"
 
+	"github.com/opencord/bbsim/api/bbsim"
 	"github.com/opencord/bbsim/internal/common"
 	dmi "github.com/opencord/device-management-interface/go/dmi"
 	log "github.com/sirupsen/logrus"
@@ -42,6 +43,7 @@
 	ponTransceiverCageUuids []string
 	root                    *dmi.Component
 	metricChannel           chan interface{}
+	eventChannel            chan interface{}
 	kafkaEndpoint           string
 	mPublisherCancelFunc    context.CancelFunc
 }
@@ -69,6 +71,7 @@
 	dmi.RegisterNativeSoftwareManagementServiceServer(grpcServer, dms)
 	dmi.RegisterNativeEventsManagementServiceServer(grpcServer, dms)
 	dmi.RegisterNativeMetricsManagementServiceServer(grpcServer, dms)
+	bbsim.RegisterBBsimDmiServer(grpcServer, dms)
 
 	reflection.Register(grpcServer)
 
diff --git a/internal/bbsim/dmiserver/dmi_event_generator.go b/internal/bbsim/dmiserver/dmi_event_generator.go
new file mode 100644
index 0000000..b25cb59
--- /dev/null
+++ b/internal/bbsim/dmiserver/dmi_event_generator.go
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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 dmiserver
+
+import (
+	"context"
+	"fmt"
+	"sync"
+
+	"github.com/golang/protobuf/ptypes"
+	"github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/device-management-interface/go/dmi"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc/codes"
+)
+
+//DmiEventsGenerator has the attributes for generating events
+type DmiEventsGenerator struct {
+	apiSrv           *DmiAPIServer
+	configuredEvents map[dmi.EventIds]dmi.EventCfg
+	access           sync.Mutex
+}
+
+// func to generate the different types of events, there are two types one with thresholds and one without
+type eventGenerationFunc func(dmi.EventIds, dmi.ComponentType)
+
+// eventGenerationUtil contains the component and the func for a specific eventId
+type eventGenerationUtil struct {
+	componentType dmi.ComponentType
+	genFunc       eventGenerationFunc
+}
+
+var dmiEG DmiEventsGenerator
+var eventGenMap map[dmi.EventIds]eventGenerationUtil
+
+func init() {
+	eventGenMap = make(map[dmi.EventIds]eventGenerationUtil)
+	eventGenMap[dmi.EventIds_EVENT_FAN_FAILURE] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_FAN,
+		genFunc:       noThresholdEventGenerationFunc,
+	}
+	eventGenMap[dmi.EventIds_EVENT_FAN_FAILURE_RECOVERED] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_FAN,
+		genFunc:       noThresholdEventGenerationFunc,
+	}
+
+	eventGenMap[dmi.EventIds_EVENT_PSU_FAILURE] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_POWER_SUPPLY,
+		genFunc:       noThresholdEventGenerationFunc,
+	}
+	eventGenMap[dmi.EventIds_EVENT_PSU_FAILURE_RECOVERED] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_POWER_SUPPLY,
+		genFunc:       noThresholdEventGenerationFunc,
+	}
+
+	eventGenMap[dmi.EventIds_EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_SENSOR,
+		genFunc:       thresholdEventGenerationFunc,
+	}
+	eventGenMap[dmi.EventIds_EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL_RECOVERED] = eventGenerationUtil{
+		componentType: dmi.ComponentType_COMPONENT_TYPE_SENSOR,
+		genFunc:       thresholdEventGenerationFunc,
+	}
+}
+
+//StartEventsGenerator initializes the event generator
+func StartEventsGenerator(apiSrv *DmiAPIServer) {
+	log.Debugf("StartEventsGenerator invoked")
+
+	dmiEG = DmiEventsGenerator{
+		apiSrv: apiSrv,
+	}
+	dmiEG.configuredEvents = make(map[dmi.EventIds]dmi.EventCfg)
+
+	// Add Fan Failure event configuration
+	dmiEG.configuredEvents[dmi.EventIds_EVENT_FAN_FAILURE] = dmi.EventCfg{
+		EventId:      dmi.EventIds_EVENT_FAN_FAILURE,
+		IsConfigured: true,
+	}
+
+	// Add hardware device temp above critical event configuration
+	dmiEG.configuredEvents[dmi.EventIds_EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL] = dmi.EventCfg{
+		EventId:      dmi.EventIds_EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL,
+		IsConfigured: true,
+		Thresholds: &dmi.Thresholds{
+			Threshold: &dmi.Thresholds_Upper{Upper: &dmi.WaterMarks{
+				High: &dmi.ValueType{
+					Val: &dmi.ValueType_IntVal{IntVal: 95},
+				},
+				Low: &dmi.ValueType{
+					Val: &dmi.ValueType_IntVal{IntVal: 90},
+				},
+			}},
+		},
+	}
+
+	// Add Power Supply Unit failure event configuration
+	dmiEG.configuredEvents[dmi.EventIds_EVENT_PSU_FAILURE] = dmi.EventCfg{
+		EventId:      dmi.EventIds_EVENT_PSU_FAILURE,
+		IsConfigured: true,
+	}
+}
+
+// get the events list
+func getEventsList() []*dmi.EventCfg {
+	events := make(map[dmi.EventIds]dmi.EventCfg)
+	dmiEG.access.Lock()
+
+	for key, value := range dmiEG.configuredEvents {
+		events[key] = value
+	}
+
+	dmiEG.access.Unlock()
+
+	var toRet []*dmi.EventCfg
+	for _, v := range events {
+		eventConfig := v
+		toRet = append(toRet, &eventConfig)
+	}
+	logger.Debugf("Events list supported by device %+v", toRet)
+	return toRet
+}
+
+//UpdateEventConfig Adds/Updates the passed event configuration
+func UpdateEventConfig(newEventCfg *dmi.EventCfg) {
+	dmiEG.access.Lock()
+	dmiEG.configuredEvents[newEventCfg.GetEventId()] = *newEventCfg
+	dmiEG.access.Unlock()
+	logger.Infof("Events updated %v", newEventCfg)
+}
+
+// update Event MetaData
+func updateEventMetaData(c *dmi.Component, apiSrv *DmiAPIServer, evt *dmi.Event) *dmi.Event {
+	evt.EventMetadata = &dmi.EventMetaData{
+		DeviceUuid: &dmi.Uuid{
+			Uuid: apiSrv.uuid,
+		},
+		ComponentUuid: c.Uuid,
+		ComponentName: c.Name,
+	}
+	return evt
+}
+
+func sendOutEventOnKafka(event interface{}, apiSrv *DmiAPIServer) {
+	select {
+	case apiSrv.eventChannel <- event:
+	default:
+		logger.Debugf("Channel not ready dropping event")
+	}
+}
+
+func noThresholdEventGenerationFunc(eventID dmi.EventIds, cType dmi.ComponentType) {
+	for _, comp := range findComponentsOfType(dmiEG.apiSrv.root.Children, cType) {
+		var evnt dmi.Event
+		evnt.EventId = eventID
+		evnt = *updateEventMetaData(comp, dmiEG.apiSrv, &evnt)
+		evnt.RaisedTs = ptypes.TimestampNow()
+		logger.Debugf("Got a No Threshold event %+v", evnt)
+		sendOutEventOnKafka(evnt, dmiEG.apiSrv)
+		break
+	}
+}
+
+func thresholdEventGenerationFunc(eventID dmi.EventIds, cType dmi.ComponentType) {
+	eventGenerated := false
+	for _, comp := range findComponentsOfType(dmiEG.apiSrv.root.Children, cType) {
+		var evnt dmi.Event
+		evnt.EventId = eventID
+		evnt = *updateEventMetaData(comp, dmiEG.apiSrv, &evnt)
+		evnt.RaisedTs = ptypes.TimestampNow()
+		configuredEvents := make(map[dmi.EventIds]dmi.EventCfg)
+
+		dmiEG.access.Lock()
+		for key, value := range dmiEG.configuredEvents {
+			configuredEvents[key] = value
+		}
+		dmiEG.access.Unlock()
+
+		for k, v := range configuredEvents {
+			if k == eventID {
+				evnt.ThresholdInfo = &dmi.ThresholdInformation{
+					ObservedValue: &dmi.ValueType{
+						Val: &dmi.ValueType_IntVal{IntVal: int64(generateRand(int32(v.Thresholds.GetUpper().GetLow().GetIntVal()), int32(v.Thresholds.GetUpper().GetHigh().GetIntVal())))},
+					},
+					Thresholds: v.GetThresholds(),
+				}
+			}
+		}
+
+		logger.Debugf("Got Threshold event %v", evnt)
+		sendOutEventOnKafka(evnt, dmiEG.apiSrv)
+		eventGenerated = true
+		if eventGenerated {
+			break
+		}
+
+	}
+}
+
+// CreateEvent creates and the passed event if it's valid and sends it to the msg bus
+func (das *DmiAPIServer) CreateEvent(ctx context.Context, evt *bbsim.DmiEvent) (*bbsim.DmiCreateEventResponse, error) {
+	retFunc := func(code codes.Code, msg string) (*bbsim.DmiCreateEventResponse, error) {
+		res := &bbsim.DmiCreateEventResponse{}
+		res.StatusCode = int32(code)
+		res.Message = msg
+		return res, nil
+	}
+
+	if dmiEG.apiSrv == nil || dmiEG.apiSrv.root == nil || dmiEG.apiSrv.root.Children == nil {
+		// inventory might not yet be created
+		return retFunc(codes.Internal, "inventory do no exist")
+	}
+
+	eventID, exists := dmi.EventIds_value[evt.EventName]
+	if !exists {
+		return retFunc(codes.NotFound,
+			fmt.Sprintf("DMI Alarm not supported. Permissible values are %s", getValidEventNames()))
+	}
+
+	genUtil, exists := eventGenMap[dmi.EventIds(eventID)]
+	if !exists {
+		return retFunc(codes.Unimplemented, "Generation of this event not yet implemented")
+	}
+
+	genUtil.genFunc(dmi.EventIds(eventID), genUtil.componentType)
+
+	return retFunc(codes.OK, "DMI Event Indication Sent.")
+
+}
+
+func getValidEventNames() string {
+	s := ""
+	//keys := make([]string, len(dmi.EventIds_value)-1)
+	for k, v := range dmi.EventIds_value {
+		if v != 0 {
+			s = s + "\n" + k
+		}
+	}
+	return s
+}
diff --git a/internal/bbsim/dmiserver/dmi_events_mgmt.go b/internal/bbsim/dmiserver/dmi_events_mgmt.go
index 3fc3416..da1e8ae 100755
--- a/internal/bbsim/dmiserver/dmi_events_mgmt.go
+++ b/internal/bbsim/dmiserver/dmi_events_mgmt.go
@@ -18,6 +18,8 @@
 
 import (
 	"context"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 
 	dmi "github.com/opencord/device-management-interface/go/dmi"
 )
@@ -25,11 +27,10 @@
 //ListEvents lists the supported events for the passed device
 func (dms *DmiAPIServer) ListEvents(ctx context.Context, req *dmi.HardwareID) (*dmi.ListEventsResponse, error) {
 	logger.Debugf("ListEvents called with request %+v", req)
-	//empty events
-	events := []*dmi.EventCfg{{}}
+	events := getEventsList()
+
 	return &dmi.ListEventsResponse{
 		Status: dmi.Status_OK_STATUS,
-		Reason: dmi.Reason_UNDEFINED_REASON,
 		Events: &dmi.EventsCfg{
 			Items: events,
 		},
@@ -39,6 +40,31 @@
 //UpdateEventsConfiguration updates the configuration of the list of events in the request
 func (dms *DmiAPIServer) UpdateEventsConfiguration(ctx context.Context, req *dmi.EventsConfigurationRequest) (*dmi.EventsConfigurationResponse, error) {
 	logger.Debugf("UpdateEventsConfiguration called with request %+v", req)
+
+	if req == nil || req.Operation == nil {
+		return &dmi.EventsConfigurationResponse{
+			Status: dmi.Status_ERROR_STATUS,
+			//TODO reason must be INVALID_PARAMS, currently this is not available in Device Management interface (DMI),
+			// change below reason with type INVALID_PARAMS once DMI is updated
+			Reason: dmi.Reason_UNDEFINED_REASON,
+		}, status.Errorf(codes.FailedPrecondition, "request is nil")
+	}
+
+	switch x := req.Operation.(type) {
+	case *dmi.EventsConfigurationRequest_Changes:
+		for _, eventConfig := range x.Changes.Items {
+			UpdateEventConfig(eventConfig)
+		}
+	case *dmi.EventsConfigurationRequest_ResetToDefault:
+		logger.Debugf("To be implemented later")
+	case nil:
+		// The field is not set.
+		logger.Debugf("Update request operation type is nil")
+		return &dmi.EventsConfigurationResponse{
+			Status: dmi.Status_UNDEFINED_STATUS,
+		}, nil
+	}
+
 	return &dmi.EventsConfigurationResponse{
 		Status: dmi.Status_OK_STATUS,
 	}, nil
diff --git a/internal/bbsim/dmiserver/dmi_hw_mgmt.go b/internal/bbsim/dmiserver/dmi_hw_mgmt.go
index cf6410d..cd0b0e9 100755
--- a/internal/bbsim/dmiserver/dmi_hw_mgmt.go
+++ b/internal/bbsim/dmiserver/dmi_hw_mgmt.go
@@ -34,7 +34,7 @@
 )
 
 const (
-	metricChannelSize = 100
+	kafkaChannelSize = 100
 )
 
 func getUUID(seed string) string {
@@ -66,9 +66,13 @@
 	dms.ponTransceiverCageUuids = make([]string, olt.NumPon)
 
 	// Start device metrics generator
-	dms.metricChannel = make(chan interface{}, metricChannelSize)
+	dms.metricChannel = make(chan interface{}, kafkaChannelSize)
 	StartMetricGenerator(dms)
 
+	// Start device event generator
+	dms.eventChannel = make(chan interface{}, kafkaChannelSize)
+	StartEventsGenerator(dms)
+
 	var components []*dmi.Component
 
 	// Create and store the component for transceivers and transceiver cages
@@ -113,11 +117,12 @@
 	}
 	components = append(components, fans...)
 
-	// Create 1 disk, 1 Processor and 1 ram
+	// Create 1 disk, 1 processor, 1 ram, 1 temperature sensor and power supply unit
 	components = append(components, createDiskComponent(0))
 	components = append(components, createProcessorComponent(0))
 	components = append(components, createMemoryComponent(0))
 	components = append(components, createInnerSurroundingTempComponentSensor(0))
+	components = append(components, createPowerSupplyComponent(0))
 
 	// create the root component
 	dms.root = &dmi.Component{
@@ -251,6 +256,25 @@
 	}
 }
 
+func createPowerSupplyComponent(psuIdx int) *dmi.Component {
+	psuName := fmt.Sprintf("Thermal/PSU/SystemPSU/%d", psuIdx)
+	psuSerial := fmt.Sprintf("bbsim-psu-serial-%d", psuIdx)
+	return &dmi.Component{
+		Name:         psuName,
+		Class:        dmi.ComponentType_COMPONENT_TYPE_POWER_SUPPLY,
+		Description:  "bbsim-psu",
+		Parent:       "",
+		ParentRelPos: 0,
+		SerialNum:    psuSerial,
+		MfgName:      "bbsim-psu",
+		IsFru:        false,
+		Uuid: &dmi.Uuid{
+			Uuid: getUUID(psuName),
+		},
+		State: &dmi.ComponentState{},
+	}
+}
+
 //StopManagingDevice stops management of a device and cleans up any context and caches for that device
 func (dms *DmiAPIServer) StopManagingDevice(ctx context.Context, req *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
 	logger.Debugf("StopManagingDevice API invoked")
@@ -452,10 +476,12 @@
 	nCtx, dms.mPublisherCancelFunc = context.WithCancel(context.Background())
 	// initialize a publisher
 	if err := InitializeDMKafkaPublishers(sarama.NewAsyncProducer, olt.ID, dms.kafkaEndpoint); err == nil {
-		// start a go routine which will read from channel and publish on kafka
+		// start a go routine which will read from channel and publish on kafka topic dm.metrics
 		go DMKafkaPublisher(nCtx, dms.metricChannel, "dm.metrics")
+		// start a go routine which will read from channel and publish on kafka topic dm.events
+		go DMKafkaPublisher(nCtx, dms.eventChannel, "dm.events")
 	} else {
-		logger.Errorf("Failed to start kafka publisher: %v", err)
+		logger.Errorf("Failed to start metric kafka publisher: %v", err)
 		return &dmi.SetRemoteEndpointResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.Reason_KAFKA_ENDPOINT_ERROR}, err
 	}
 
diff --git a/internal/bbsim/dmiserver/dmi_kafka_producer.go b/internal/bbsim/dmiserver/dmi_kafka_producer.go
index 9ee0172..8955dfa 100755
--- a/internal/bbsim/dmiserver/dmi_kafka_producer.go
+++ b/internal/bbsim/dmiserver/dmi_kafka_producer.go
@@ -26,7 +26,7 @@
 	log "github.com/sirupsen/logrus"
 )
 
-var metricsProducer sarama.AsyncProducer
+var producer sarama.AsyncProducer
 
 // InitializeDMKafkaPublishers initializes  metrics kafka publisher
 func InitializeDMKafkaPublishers(NewAsyncProducer func([]string, *sarama.Config) (sarama.AsyncProducer, error), oltID int, msgBusEndPoint string) error {
@@ -37,9 +37,9 @@
 	config.Producer.Retry.Max = 5
 	config.Metadata.Retry.Max = 10
 	config.Metadata.Retry.Backoff = 10 * time.Second
-	config.ClientID = "BBSim-OLT-Metrics-" + strconv.Itoa(oltID)
+	config.ClientID = "BBSim-OLT-DMIServer-" + strconv.Itoa(oltID)
 
-	metricsProducer, err = NewAsyncProducer([]string{msgBusEndPoint}, config)
+	producer, err = NewAsyncProducer([]string{msgBusEndPoint}, config)
 	return err
 }
 
@@ -49,16 +49,16 @@
 loop:
 	for {
 		select {
-		case metric := <-ch:
-			log.Tracef("Writing to kafka topic(%s): %v", topic, metric)
-			jsonMet, err := json.Marshal(metric)
+		case data := <-ch:
+			log.Tracef("Writing to kafka topic(%s): %v", topic, data)
+			jsonData, err := json.Marshal(data)
 			if err != nil {
-				log.Errorf("Failed to get json metric %v", err)
+				log.Errorf("Failed to get json %v", err)
 				continue
 			}
-			metricsProducer.Input() <- &sarama.ProducerMessage{
+			producer.Input() <- &sarama.ProducerMessage{
 				Topic: topic,
-				Value: sarama.ByteEncoder(jsonMet),
+				Value: sarama.ByteEncoder(jsonData),
 			}
 		case <-ctx.Done():
 			log.Infof("Stopping DM Kafka Publisher for topic %s", topic)
diff --git a/internal/bbsim/dmiserver/dmi_metrics_mgmt.go b/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
index cb88cc7..e23786f 100755
--- a/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
+++ b/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
@@ -79,7 +79,7 @@
 	if req == nil || req.GetMetricId() < 0 {
 		return &dmi.GetMetricResponse{
 			Status: dmi.Status_ERROR_STATUS,
-			//TODO reason must be INVALID_PARAMS, currently this is available in Device Management interface (DMI),
+			//TODO reason must be INVALID_PARAMS, currently this is not available in Device Management interface (DMI),
 			// change below reason with type INVALID_PARAMS once DMI is updated
 			Reason: dmi.Reason_UNDEFINED_REASON,
 			Metric: &dmi.Metric{},
diff --git a/internal/bbsimctl/commands/dmi_events.go b/internal/bbsimctl/commands/dmi_events.go
new file mode 100644
index 0000000..1608965
--- /dev/null
+++ b/internal/bbsimctl/commands/dmi_events.go
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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 commands
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/jessevdk/go-flags"
+	"github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsimctl/config"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+)
+
+type DMIOptions struct {
+	Events DmiEventOptions `command:"events"`
+}
+
+type DmiEventCreate struct {
+	Args struct {
+		Name string
+	} `positional-args:"yes" required:"yes"`
+}
+
+type DmiEventOptions struct {
+	Create DmiEventCreate `command:"create"`
+}
+
+func RegisterDMICommands(parser *flags.Parser) {
+	_, _ = parser.AddCommand("dmi", "DMI Commands", "Commands to create events", &DMIOptions{})
+}
+
+func dmiEventGrpcClient() (bbsim.BBsimDmiClient, *grpc.ClientConn) {
+	conn, err := grpc.Dial(config.DmiConfig.Server, grpc.WithInsecure())
+	if err != nil {
+		log.Errorf("BBsimDmiClient connection failed  : %v", err)
+		return nil, conn
+	}
+	return bbsim.NewBBsimDmiClient(conn), conn
+}
+
+// Execute create event
+func (o *DmiEventCreate) Execute(args []string) error {
+	client, conn := dmiEventGrpcClient()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	req := bbsim.DmiEvent{EventName: o.Args.Name}
+	res, err := client.CreateEvent(ctx, &req)
+	if err != nil {
+		log.Errorf("Cannot create DMI event: %v", err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+	return nil
+}
diff --git a/internal/bbsimctl/commands/onualarms.go b/internal/bbsimctl/commands/onualarms.go
index fb1d00e..669c173 100755
--- a/internal/bbsimctl/commands/onualarms.go
+++ b/internal/bbsimctl/commands/onualarms.go
@@ -20,10 +20,11 @@
 import (
 	"context"
 	"fmt"
-	"github.com/opencord/bbsim/internal/common"
 	"os"
 	"strings"
 
+	"github.com/opencord/bbsim/internal/common"
+
 	"github.com/jessevdk/go-flags"
 	"github.com/olekukonko/tablewriter"
 	pb "github.com/opencord/bbsim/api/bbsim"
diff --git a/internal/bbsimctl/config/config.go b/internal/bbsimctl/config/config.go
index 7d11122..4bf762a 100644
--- a/internal/bbsimctl/config/config.go
+++ b/internal/bbsimctl/config/config.go
@@ -57,6 +57,13 @@
 	},
 }
 
+var DmiConfig = GlobalConfigSpec{
+	Server: "localhost:50075",
+	Grpc: GrpcConfigSpec{
+		Timeout: time.Second * 10,
+	},
+}
+
 func ProcessGlobalOptions() {
 	if len(GlobalOptions.Config) == 0 {
 		home, err := os.UserHomeDir()