/**
  * Create command invocations for an assignment.
  *
  * @param assignment
  * @param date
  * @param commands
  * @return
  * @throws SiteWhereException
  */
 protected List<IDeviceCommandInvocation> createDeviceCommandInvocations(
     IDeviceAssignment assignment, Date date, List<IDeviceCommand> commands)
     throws SiteWhereException {
   long current = date.getTime();
   List<IDeviceCommandInvocation> invocations = new ArrayList<IDeviceCommandInvocation>();
   for (IDeviceCommand command : commands) {
     DeviceCommandInvocationCreateRequest request = new DeviceCommandInvocationCreateRequest();
     request.setCommandToken(command.getToken());
     request.setInitiator(CommandInitiator.REST);
     request.setInitiatorId("system");
     request.setTarget(CommandTarget.Assignment);
     request.setTargetId(assignment.getToken());
     request.setStatus(CommandStatus.Pending);
     request.setEventDate(new Date(current));
     Map<String, String> values = new HashMap<String, String>();
     for (ICommandParameter param : command.getParameters()) {
       values.put(param.getName(), getSampleValue(param.getType()));
     }
     request.setParameterValues(values);
     invocations.add(
         getDeviceManagement()
             .addDeviceCommandInvocation(assignment.getToken(), command, request));
     current += 30000;
   }
   return invocations;
 }
 /**
  * Create example state change events.
  *
  * @param assignment
  * @param start
  * @return
  * @throws SiteWhereException
  */
 protected List<IDeviceStateChange> createDeviceStateChanges(
     IDeviceAssignment assignment, IDeviceSpecification specification, Date start)
     throws SiteWhereException {
   List<IDeviceStateChange> stateChanges = new ArrayList<IDeviceStateChange>();
   DeviceRegistrationRequest register = new DeviceRegistrationRequest();
   register.setHardwareId(assignment.getDeviceHardwareId());
   register.setSpecificationToken(specification.getToken());
   register.setEventDate(start);
   stateChanges.add(getDeviceManagement().addDeviceStateChange(assignment.getToken(), register));
   return stateChanges;
 }
  /**
   * Create devices for a site and assign them.
   *
   * @param site
   * @return
   * @throws SiteWhereException
   */
  public List<DeviceAssignment> createAssignments(
      ISite site, Map<String, SpecificationDetails> specMap) throws SiteWhereException {
    Date before = new Date(System.currentTimeMillis() - (2 * 60 * 60 * 1000));
    List<DeviceAssignment> results = new ArrayList<DeviceAssignment>();
    DeviceAssignmentMarshalHelper helper =
        new DeviceAssignmentMarshalHelper(getDeviceManagement().getTenant());
    helper.setIncludeDevice(true);
    for (int x = 0; x < ASSIGNMENTS_PER_SITE; x++) {
      IDeviceSpecification specification = getRandomDeviceSpecification();

      // Make sure most of the entries are heavy equipment.
      if (Math.random() > 0.7) {
        specification = getMeitrackSpecification();
      }
      SpecificationDetails info = specMap.get(specification.getToken());
      AssignmentChoice assnChoice = getRandomAssignmentChoice(info);
      // List<IDeviceCommand> commands =
      // commandsBySpecToken.get(specification.getToken());

      // Create device.
      DeviceCreateRequest request = new DeviceCreateRequest();
      request.setHardwareId(UUID.randomUUID().toString());
      request.setSpecificationToken(specification.getToken());
      request.setSiteToken(site.getToken());
      request.setComments(assnChoice.getDeviceDescriptionBase() + " " + (x + 1) + ".");
      IDevice device = getDeviceManagement().createDevice(request);
      LOGGER.info(PREFIX_CREATE_DEVICE + " " + device.getHardwareId());

      // Create assignment.
      DeviceAssignmentCreateRequest assnRequest = new DeviceAssignmentCreateRequest();
      assnRequest.setAssignmentType(DeviceAssignmentType.Associated);
      assnRequest.setAssetModuleId(assnChoice.getAssignmentAssetModuleId());
      assnRequest.setAssetId(assnChoice.getAssignmentAssetId());
      assnRequest.setDeviceHardwareId(device.getHardwareId());
      Map<String, String> metadata = new HashMap<String, String>();
      metadata.put("serialNumber", UUID.randomUUID().toString());
      assnRequest.setMetadata(metadata);
      IDeviceAssignment assignment = getDeviceManagement().createDeviceAssignment(assnRequest);
      LOGGER.info(PREFIX_CREATE_ASSIGNMENT + " " + assignment.getToken());

      // Create events for assignment.
      createDeviceMeasurements(assignment, before);
      createDeviceLocations(assignment, before);
      // List<IDeviceCommandInvocation> invocations =
      // createDeviceCommandInvocations(assignment, before, commands);
      // createDeviceCommandResponses(assignment, before, invocations);
      // createDeviceStateChanges(assignment, specification, before);

      results.add(helper.convert(assignment, assetModuleManager));
    }
    return results;
  }
 public Builder(IDeviceAssignment api) {
   request.setToken(api.getToken());
   request.setDeviceHardwareId(api.getDeviceHardwareId());
   request.setAssetModuleId(api.getAssetModuleId());
   request.setAssetId(api.getAssetId());
   request.setAssignmentType(api.getAssignmentType());
   if (api.getMetadata() != null) {
     request.setMetadata(new HashMap<String, String>());
     request.getMetadata().putAll(api.getMetadata());
   }
 }
 /**
  * Create command responses for each invocation.
  *
  * @param assignment
  * @param date
  * @param invocations
  * @return
  * @throws SiteWhereException
  */
 protected List<IDeviceCommandResponse> createDeviceCommandResponses(
     IDeviceAssignment assignment, Date date, List<IDeviceCommandInvocation> invocations)
     throws SiteWhereException {
   long current = date.getTime();
   List<IDeviceCommandResponse> responses = new ArrayList<IDeviceCommandResponse>();
   for (IDeviceCommandInvocation invocation : invocations) {
     DeviceCommandResponseCreateRequest request = new DeviceCommandResponseCreateRequest();
     request.setOriginatingEventId(invocation.getId());
     request.setResponse("ACK");
     request.setEventDate(new Date(current));
     responses.add(getDeviceManagement().addDeviceCommandResponse(assignment.getToken(), request));
     current += 30000;
   }
   return responses;
 }
  /**
   * Create device locations in a path near the main zone.
   *
   * @param assignment
   * @param start
   * @return
   * @throws SiteWhereException
   */
  protected List<IDeviceLocation> createDeviceLocations(IDeviceAssignment assignment, Date date)
      throws SiteWhereException {
    long current = date.getTime();
    Polygon zone = GeoUtils.createPolygonForLocations(zoneLocations);
    Point centroid = zone.getCentroid();

    // Calculate length of steps between locations based on bounding circle.
    MinimumBoundingCircle circle = new MinimumBoundingCircle(zone);
    double step = circle.getRadius() / 10;

    double cx = centroid.getX();
    double cy = centroid.getY();
    double deltaX = (Math.sqrt(Math.random()) * step * 2) - step;
    double deltaY = (Math.sqrt(Math.random()) * step * 2) - step;

    // Used to rotate deltas to turn path and stay inside polygon.
    AffineTransformation xform = new AffineTransformation();
    xform.rotate(Math.toRadians(22.5));

    List<IDeviceLocation> results = new ArrayList<IDeviceLocation>();
    GeometryFactory factory = new GeometryFactory();
    for (int x = 0; x < LOCATIONS_PER_ASSIGNMENT; x++) {
      boolean foundNext = false;

      // Add a little randomness to path.
      double waver = ((Math.random() * 20) - 10.0);
      AffineTransformation waverXform = new AffineTransformation();
      waverXform.rotate(Math.toRadians(waver));
      Coordinate waverDelta = new Coordinate(deltaX, deltaY);
      waverXform.transform(waverDelta, waverDelta);
      deltaX = waverDelta.x;
      deltaY = waverDelta.y;

      while (!foundNext) {
        Coordinate start = new Coordinate(cx, cy);
        Coordinate end = new Coordinate(cx + deltaX, cy + deltaY);
        Coordinate[] lineCoords = {start, end};
        LineString line = factory.createLineString(lineCoords);
        if (zone.contains(line)) {
          DeviceLocationCreateRequest request = new DeviceLocationCreateRequest();
          request.setLatitude(end.y);
          request.setLongitude(end.x);
          request.setElevation(0.0);
          request.setEventDate(new Date(current));
          IDeviceLocation created =
              getDeviceManagement().addDeviceLocation(assignment.getToken(), request);
          results.add(created);

          cx = cx + deltaX;
          cy = cy + deltaY;
          foundNext = true;
        } else {
          // Rotate deltas and try again.
          Coordinate delta = new Coordinate(deltaX, deltaY);
          xform.transform(delta, delta);
          deltaX = delta.x;
          deltaY = delta.y;
        }
      }
      current += 30000;
    }
    LOGGER.info(PREFIX_CREATE_EVENTS + " " + results.size() + " locations. ");
    return results;
  }
  /**
   * Create device measurements associated with an assignment.
   *
   * @param assignment
   * @return
   * @throws SiteWhereException
   */
  protected List<IDeviceMeasurements> createDeviceMeasurements(
      IDeviceAssignment assignment, Date start) throws SiteWhereException {
    long current = start.getTime();
    double temp = MIN_TEMP;
    double fuel = 100;
    double delta = 4;
    double mult = 6;
    int measurementCount = 0;
    int alertCount = 0;
    List<IDeviceMeasurements> results = new ArrayList<IDeviceMeasurements>();
    for (int x = 0; x < EVENTS_PER_ASSIGNMENT; x++) {
      // Simulate temperature changes.
      temp = temp + (delta + ((Math.random() * mult * 2) - mult));
      temp = Math.round(temp * 100.0) / 100.0;
      if ((temp > MAX_TEMP) || (temp < MIN_TEMP)) {
        delta = -delta;
      }

      // Simulate fuel changes.
      fuel -= (Math.random() * 2);
      fuel = Math.round(fuel * 100.0) / 100.0;
      if (fuel < 0) {
        fuel = 0;
      }

      // Store current temperature measurement.
      DeviceMeasurementsCreateRequest mreq = new DeviceMeasurementsCreateRequest();
      mreq.addOrReplaceMeasurement("engine.temperature", temp);
      mreq.addOrReplaceMeasurement("fuel.level", fuel);
      mreq.setEventDate(new Date(current));
      results.add(getDeviceManagement().addDeviceMeasurements(assignment.getToken(), mreq));
      measurementCount++;

      // Create alerts based on current temperature.
      if (temp > WARN_TEMP) {
        DeviceAlertCreateRequest areq = new DeviceAlertCreateRequest();
        areq.setType("engine.overheat");
        areq.setEventDate(new Date(current));
        areq.setMessage("Engine temperature is at top of operating range.");
        areq.setLevel(AlertLevel.Warning);
        if (temp > ERROR_TEMP) {
          areq.setMessage("Engine temperature is at a dangerous level.");
          areq.setLevel(AlertLevel.Error);
        } else if (temp > CRITICAL_TEMP) {
          areq.setMessage("Engine temperature critical. Shutting down.");
          areq.setLevel(AlertLevel.Critical);
          break;
        }
        getDeviceManagement().addDeviceAlert(assignment.getToken(), areq);
        alertCount++;
      }

      current += 10000;
    }
    LOGGER.info(
        PREFIX_CREATE_EVENTS
            + " "
            + measurementCount
            + " measurements. "
            + alertCount
            + " alerts.");
    return results;
  }